blob: 8f0992ff05487fca02a89891b46bebcfb471c56f [file] [log] [blame]
/**
* @file
*
* Southbridge Initial routine
*
*
*
* @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"
//
// Declaration of local functions
//
VOID
hwmInitRegister (
IN AMDSBCFG* pConfig
);
VOID
hwmGetRawData (
IN AMDSBCFG* pConfig
);
VOID
hwmCaculate (
IN AMDSBCFG* pConfig
);
VOID
hwmGetCalibrationFactor (
IN AMDSBCFG* pConfig
);
VOID
hwmProcessParameter (
IN AMDSBCFG* pConfig
);
VOID
hwmSetRegister (
IN AMDSBCFG* pConfig
);
HWM_temp_par_struct tempParDefault[] = {
{ 5219, 27365 , 0 },
{ 5222, 27435 , 0 },
{ 5219, 27516 , BIT0 }, //High Ratio
{ 5221, 27580 , BIT1 }, //High Current
{ 5123, 27866 , 0 }
};
//#ifndef NO_HWM_SUPPORT
/**
* hwmInitRegister - Init Hardware Monitor Register.
*
*
* @param[in] pConfig Southbridge configuration structure pointer.
*
*/
VOID
hwmInitRegister (
IN AMDSBCFG* pConfig
)
{
UINT32 LinearRangeOutLimit;
RWMEM (ACPI_MMIO_BASE + PMIO2_BASE + 0xB2, AccWidthUint8, 0, 0x55);
RWMEM (ACPI_MMIO_BASE + PMIO2_BASE + 0xB3, AccWidthUint8, 0, 0x55);
RWMEM (ACPI_MMIO_BASE + PMIO2_BASE + 0x91, AccWidthUint8, 0, 0x55);
RWMEM (ACPI_MMIO_BASE + PMIO2_BASE + 0x92, AccWidthUint8, 0, 0x55);
RWMEM (ACPI_MMIO_BASE + PMIO2_BASE + 0x00, AccWidthUint8, 0, 0x06);
RWMEM (ACPI_MMIO_BASE + PMIO2_BASE + 0x10, AccWidthUint8, 0, 0x06);
RWMEM (ACPI_MMIO_BASE + PMIO2_BASE + 0x20, AccWidthUint8, 0, 0x06);
RWMEM (ACPI_MMIO_BASE + PMIO2_BASE + 0x30, AccWidthUint8, 0, 0x06);
RWMEM (ACPI_MMIO_BASE + PMIO2_BASE + 0x40, AccWidthUint8, 0, 0x06);
RWMEM (ACPI_MMIO_BASE + PMIO2_BASE + 0x66, AccWidthUint8, 0, 0x01);
RWMEM (ACPI_MMIO_BASE + PMIO2_BASE + 0x6B, AccWidthUint8, 0, 0x01);
RWMEM (ACPI_MMIO_BASE + PMIO2_BASE + 0x70, AccWidthUint8, 0, 0x01);
RWMEM (ACPI_MMIO_BASE + PMIO2_BASE + 0x75, AccWidthUint8, 0, 0x01);
RWMEM (ACPI_MMIO_BASE + PMIO2_BASE + 0x7A, AccWidthUint8, 0, 0x01);
RWMEM (ACPI_MMIO_BASE + PMIO2_BASE + 0xE6, AccWidthUint8, 0xff, 0x02);
RWMEM (ACPI_MMIO_BASE + PMIO2_BASE + 0xF8, AccWidthUint8, 0, 0x05);
RWMEM (ACPI_MMIO_BASE + PMIO2_BASE + 0xF9, AccWidthUint8, 0, 0x06);
RWMEM (ACPI_MMIO_BASE + PMIO2_BASE + 0xFF, AccWidthUint8, 0, 0x42);
RWMEM (ACPI_MMIO_BASE + PMIO2_BASE + 0xE9, AccWidthUint8, 0, 0xFF);
RWMEM (ACPI_MMIO_BASE + PMIO2_BASE + 0xEB, AccWidthUint8, 0, 0x1F);
//2.13 HWM Sensor Clk
RWMEM (ACPI_MMIO_BASE + PMIO2_BASE + 0xEF, AccWidthUint8, 0, 0x0A);
RWMEM (ACPI_MMIO_BASE + PMIO2_BASE + 0xFB, AccWidthUint8, 0, 0x00);
//2.9 Enhancement of FanOut0 Control
//check for fanLinearEnhanceEn
if (pConfig->hwm.fanLinearEnhanceEn == 0) {
RWMEM (ACPI_MMIO_BASE + MISC_BASE + SB_MISC_REG50, AccWidthUint32, ~ BIT11, BIT11);
LinearRangeOutLimit = (UINT32) (pConfig->hwm.fanLinearRangeOutLimit);
LinearRangeOutLimit = LinearRangeOutLimit << 20;
RWMEM (ACPI_MMIO_BASE + PMIO_BASE + SB_PMIOA_REGB4, AccWidthUint32, 0xFF0FFFFF, LinearRangeOutLimit);
} else {
RWMEM (ACPI_MMIO_BASE + MISC_BASE + SB_MISC_REG50, AccWidthUint32, ~ BIT11, 0);
}
//check for fanLinearHoldFix
if (pConfig->hwm.fanLinearHoldFix == 0) {
RWMEM (ACPI_MMIO_BASE + MISC_BASE + SB_MISC_REG50, AccWidthUint32, ~ BIT20, BIT20);
} else {
RWMEM (ACPI_MMIO_BASE + MISC_BASE + SB_MISC_REG50, AccWidthUint32, ~ BIT20, 0);
}
}
/**
* hwmSbtsiAutoPolling - Hardware Monitor Auto Poll SB-TSI.
*
*
* @param[in] pConfig Southbridge configuration structure pointer.
*
*/
VOID
hwmSbtsiAutoPolling (
IN AMDSBCFG* pConfig
)
{
UINT8 dbValue;
UINT16 smbusBase;
smbusBase = (UINT16) (pConfig->BuildParameters.Smbus0BaseAddress);
if (pConfig->hwm.hwmSbtsiAutoPoll == 1) {
hwmSbtsiAutoPollingPause (pConfig);
RWMEM (ACPI_MMIO_BASE + PMIO_BASE + SB_PMIOA_REG2E, AccWidthUint8, ~(BIT1 + BIT2), BIT2);
dbValue = 0xff;
WriteIO (smbusBase, AccWidthUint8, &dbValue);
dbValue = 0x08;
WriteIO (smbusBase + 2, AccWidthUint8, &dbValue);
dbValue = 0x09;
WriteIO (smbusBase + 3, AccWidthUint8, &dbValue);
dbValue = 0x98;
WriteIO (smbusBase + 4, AccWidthUint8, &dbValue);
if ( IsSbA11 () ) {
dbValue = 0x00;
} else {
dbValue = 0x20;
}
WriteIO (smbusBase + 5, AccWidthUint8, &dbValue);
dbValue = 0x48;
WriteIO (smbusBase + 2, AccWidthUint8, &dbValue);
ReadIO (smbusBase + 0, AccWidthUint8, &dbValue);
while ( dbValue & BIT0 ) {
ReadIO (smbusBase + 0, AccWidthUint8, &dbValue);
}
if ( IsSbA11 () ) {
dbValue = 0x09;
} else {
dbValue = 0x08;
}
WriteIO (smbusBase + 2, AccWidthUint8, &dbValue);
if ( IsSbA11 () ) {
dbValue = 0x01;
} else {
dbValue = 0x10;
}
WriteIO (smbusBase + 3, AccWidthUint8, &dbValue);
dbValue = 0x99;
WriteIO (smbusBase + 4, AccWidthUint8, &dbValue);
if ( IsSbA11 () ) {
dbValue = 0x0f;
WriteIO (smbusBase + 0x14, AccWidthUint8, &dbValue);
}
if ( IsSbA12Plus () ) {
dbValue = 0x80;
WriteIO (smbusBase + 0x14, AccWidthUint8, &dbValue);
dbValue = 0x01;
WriteIO (smbusBase + 0x17, AccWidthUint8, &dbValue);
dbValue = 0x81;
WriteIO (smbusBase + 0x14, AccWidthUint8, &dbValue);
}
//map SB-TSI to tempin0
RWMEM (ACPI_MMIO_BASE + PMIO2_BASE + SB_PMIO2_REG92, AccWidthUint8, ~BIT3, BIT3);
dbValue = 0x00;
WriteIO (smbusBase + 0x16, AccWidthUint8, &dbValue);
pConfig->hwm.hwmSbtsiAutoPollStarted = TRUE;
} else {
hwmSbtsiAutoPollingOff (pConfig);
}
}
/**
* hwmSbtsiAutoPollingOff - Hardware Monitor Auto Poll SB-TSI
* Off.
*
*
* @param[in] pConfig Southbridge configuration structure pointer.
*
*/
VOID
hwmSbtsiAutoPollingOff (
IN AMDSBCFG* pConfig
)
{
UINT8 dbValue;
UINT16 smbusBase;
if ( pConfig->hwm.hwmEnable ) {
smbusBase = (UINT16) (pConfig->BuildParameters.Smbus0BaseAddress);
dbValue = 0x00;
WriteIO (smbusBase + 0x14, AccWidthUint8, &dbValue);
hwmSbtsiAutoPollingPause (pConfig);
RWMEM (ACPI_MMIO_BASE + PMIO_BASE + SB_PMIOA_REG2E, AccWidthUint8, ~(BIT1 + BIT2), 0);
RWMEM (ACPI_MMIO_BASE + PMIO2_BASE + SB_PMIO2_REG92, AccWidthUint8, ~BIT3, 0x00);
pConfig->hwm.hwmSbtsiAutoPollStarted = FALSE;
}
}
/**
* hwmSbtsiAutoPollingPause - Pause Hardware Monitor Auto Poll
* SB-TSI Off.
*
*
* @param[in] pConfig Southbridge configuration structure pointer.
*
*/
VOID
hwmSbtsiAutoPollingPause (
IN AMDSBCFG* pConfig
)
{
UINT8 dbValue;
UINT16 smbusBase;
if ( pConfig->hwm.hwmEnable && (pConfig->hwm.hwmSbtsiAutoPoll == 1) ) {
smbusBase = (UINT16) (pConfig->BuildParameters.Smbus0BaseAddress);
dbValue = 0x01;
WriteIO (smbusBase + 0x16, AccWidthUint8, &dbValue);
dbValue = 0x00;
while ( dbValue == 0x00 ) {
ReadIO (smbusBase + 0x16, AccWidthUint8, &dbValue);
}
}
}
/**
* hwmGetRawData - Hardware Monitor Get Raw Data.
*
*
* @param[in] pConfig Southbridge configuration structure pointer.
*
*/
VOID
hwmGetRawData (
IN AMDSBCFG* pConfig
)
{
UINT8 i;
UINT16 dwValue;
//_asm { jmp $ };
//fan speed
for ( i = 0; i < 5 ; i++ ) {
ReadPMIO2 (SB_PMIO2_REG69 + i * 5, AccWidthUint16, &dwValue);
if ( (dwValue & 0xFFC0) != 0xFFC0 ) {
pConfig->hwm.hwmCurrentRaw.fanSpeed[i] = dwValue;
} else {
pConfig->hwm.hwmCurrentRaw.fanSpeed[i] = 0xFFFF;
}
}
//temperatue
for ( i = 0; i < 5 ; i++ ) {
ReadPMIO2 (SB_PMIO2_REG95 + i * 4, AccWidthUint16, &dwValue);
if ( ( i == 1 ) || (dwValue > 0x4000) ) {
pConfig->hwm.hwmCurrentRaw.temperature[i] = dwValue;
}
}
//voltage
for ( i = 0; i < 8 ; i++ ) {
ReadPMIO2 (SB_PMIO2_REGB8 + i * 4, AccWidthUint16, &dwValue);
if ( (dwValue & 0xFFC0) != 0xFFC0 ) {
pConfig->hwm.hwmCurrentRaw.voltage[i] = dwValue;
}
}
}
/**
* hwmCaculate - Hardware Monitor Caculate Raw Data to Display Data.
*
*
* @param[in] pConfig Southbridge configuration structure pointer.
*
*/
VOID
hwmCaculate (
IN AMDSBCFG* pConfig
)
{
UINT8 i;
UINT16 dwValue;
//UINT32 ddValue;
//fan speed
for ( i = 0; i < 5 ; i++ ) {
dwValue = pConfig->hwm.hwmCurrentRaw.fanSpeed[i];
if ((dwValue == 0xffff) || (dwValue == 0x0000)) {
pConfig->hwm.hwmCurrent.fanSpeed[i] = 0;
} else {
pConfig->hwm.hwmCurrent.fanSpeed[i] = ( 22720 >> pConfig->hwm.fanSampleFreqDiv ) * 60 / dwValue / 2;
}
}
//temperatue
for ( i = 0; i < 5 ; i++ ) {
dwValue = pConfig->hwm.hwmCurrentRaw.temperature[i];
if ((pConfig->hwm.hwmSbtsiAutoPoll == 1) && (i == 1)) {
if ( IsSbA11 () ) {
dwValue = (dwValue >> 8) * 10;
} else {
dwValue = ((dwValue & 0xff00) >> 8) * 10 + (((dwValue & 0x00ff) * 10 ) >> 8);
}
} else {
dwValue = ((dwValue << 3) * pConfig->hwm.hwmTempPar[i].At / pConfig->hwm.hwmCalibrationFactor / 100 - pConfig->hwm.hwmTempPar[i].Ct) / 10 ;
}
if ( pConfig->hwm.hwmCurrentRaw.temperature[i] == 0 ) {
dwValue = 0;
}
if ( dwValue < 10000 ) {
pConfig->hwm.hwmCurrent.temperature[i] = dwValue;
} else {
pConfig->hwm.hwmCurrent.temperature[i] = 0;
}
}
//voltage
for ( i = 0; i < 8 ; i++ ) {
dwValue = pConfig->hwm.hwmCurrentRaw.voltage[i];
pConfig->hwm.hwmCurrent.voltage[i] = (dwValue >> 6) * 512 / pConfig->hwm.hwmCalibrationFactor;
}
}
/**
* hwmGetCalibrationFactor - Hardware Monitor Get Calibration
* Factor
*
*
* @param[in] pConfig Southbridge configuration structure pointer.
*
*/
VOID
hwmGetCalibrationFactor (
IN AMDSBCFG* pConfig
)
{
UINT8 dbValue;
// UINT16 dwValue;
// UINT32 ddValue;
//temperatue parameter
ReadPMIO2 (SB_PMIO2_REGEA, AccWidthUint8, &dbValue);
if ( dbValue & BIT7 ) {
if ( dbValue & BIT6 ) {pConfig->hwm.hwmCalibrationFactor = 0x100 + dbValue;
} else {pConfig->hwm.hwmCalibrationFactor = 0x200 + (dbValue & 0x3f ); }
} else {
pConfig->hwm.hwmCalibrationFactor = 0x200;
}
}
/**
* hwmProcessParameter - Hardware Monitor process Parameter
*
*
* @param[in] pConfig Southbridge configuration structure pointer.
*
*/
VOID
hwmProcessParameter (
IN AMDSBCFG* pConfig
)
{
UINT8 i;
UINT8 tempChannel;
UINT8 dbValue;
UINT16 dwValue;
// UINT32 ddValue;
hwmGetCalibrationFactor (pConfig);
//temperatue parameter
for ( i = 0; i < 5 ; i++ ) {
if ( pConfig->hwm.hwmTempPar[i].At == 0 ) {
pConfig->hwm.hwmTempPar[i] = tempParDefault[i];
}
}
for ( i = 0; i < 5 ; i++ ) {
if ( pConfig->hwm.hwmFanControl[i].LowDuty_reg03 == 100 ) {
pConfig->hwm.hwmFanControlCooked[i].LowDuty_reg03 = 255;
} else {
pConfig->hwm.hwmFanControlCooked[i].LowDuty_reg03 = (pConfig->hwm.hwmFanControl[i].LowDuty_reg03 << 8) / 100;
}
if ( pConfig->hwm.hwmFanControl[i].MedDuty_reg04 == 100 ) {
pConfig->hwm.hwmFanControlCooked[i].MedDuty_reg04 = 255;
} else {
pConfig->hwm.hwmFanControlCooked[i].MedDuty_reg04 = (pConfig->hwm.hwmFanControl[i].MedDuty_reg04 << 8) / 100;
}
if ( pConfig->hwm.hwmFanControl[i].HighTemp_reg0A > pConfig->hwm.hwmFanControl[i].MedTemp_reg08 ) {
dbValue = (UINT8) ((256 - pConfig->hwm.hwmFanControlCooked[i].LowDuty_reg03) / (pConfig->hwm.hwmFanControl[i].HighTemp_reg0A - pConfig->hwm.hwmFanControl[i].MedTemp_reg08));
} else {
dbValue = (UINT8) ((256 - pConfig->hwm.hwmFanControlCooked[i].LowDuty_reg03));
}
dwValue = pConfig->hwm.hwmFanControl[i].LowTemp_reg06;
if (pConfig->hwm.hwmFanControl[i].InputControl_reg00 > 4) {
tempChannel = 0;
} else {
tempChannel = pConfig->hwm.hwmFanControl[i].InputControl_reg00;
}
if ((pConfig->hwm.hwmSbtsiAutoPoll == 1) && (i == 0)) {
dwValue = dwValue << 8;
} else {
dbValue = (UINT8) (dbValue * 10000 * pConfig->hwm.hwmCalibrationFactor / pConfig->hwm.hwmTempPar[tempChannel].At / 512);
dwValue = ((dwValue * 100 + pConfig->hwm.hwmTempPar[tempChannel].Ct ) * 100 * pConfig->hwm.hwmCalibrationFactor / pConfig->hwm.hwmTempPar[tempChannel].At) >> 3;
}
pConfig->hwm.hwmFanControlCooked[i].LowTemp_reg06 = dwValue;
pConfig->hwm.hwmFanControlCooked[i].Multiplier_reg05 = dbValue & 0x3f;
dwValue = pConfig->hwm.hwmFanControl[i].MedTemp_reg08;
if ((pConfig->hwm.hwmSbtsiAutoPoll == 1) && (i == 0)) {
dwValue = dwValue << 8;
} else {
dwValue = ((dwValue * 100 + pConfig->hwm.hwmTempPar[tempChannel].Ct ) * 100 * pConfig->hwm.hwmCalibrationFactor / pConfig->hwm.hwmTempPar[tempChannel].At) >> 3;
}
pConfig->hwm.hwmFanControlCooked[i].MedTemp_reg08 = dwValue;
dwValue = pConfig->hwm.hwmFanControl[i].HighTemp_reg0A;
if ((pConfig->hwm.hwmSbtsiAutoPoll == 1) && (i == 0)) {
dwValue = dwValue << 8;
} else {
dwValue = ((dwValue * 100 + pConfig->hwm.hwmTempPar[tempChannel].Ct ) * 100 * pConfig->hwm.hwmCalibrationFactor / pConfig->hwm.hwmTempPar[tempChannel].At) >> 3;
}
pConfig->hwm.hwmFanControlCooked[i].HighTemp_reg0A = dwValue;
}
}
/**
* hwmSetRegister - Hardware Monitor Set Parameter
*
*
* @param[in] pConfig Southbridge configuration structure pointer.
*
*/
VOID
hwmSetRegister (
IN AMDSBCFG* pConfig
)
{
UINT8 *pDbValue;
UINT8 i;
UINT8 registerN;
UINT8 registerPM2RegF8;
UINT8 registerPM2RegF9;
//UINT16 dwValue;
// UINT32 ddValue;
//Configure Fans
for ( i = 0; i < 5 ; i++ ) {
pDbValue = &(pConfig->hwm.hwmFanControlCooked[i].InputControl_reg00);
for ( registerN = 0; registerN < 0x0E ; registerN++ ) {
WritePMIO2 (i * 0x10 + registerN, AccWidthUint8, pDbValue);
pDbValue ++;
}
}
//Configure Sample Frequency Divider
WritePMIO2 (SB_PMIO2_REG63, AccWidthUint8, &(pConfig->hwm.fanSampleFreqDiv));
//Configure Mode
ReadPMIO2 (0xF8, AccWidthUint8, &registerPM2RegF8);
ReadPMIO2 (0xF9, AccWidthUint8, &registerPM2RegF9);
for ( i = 0; i < 5 ; i++ ) {
if (pConfig->hwm.hwmTempPar[i].Mode == BIT0) {
registerPM2RegF8 |= 1 << (i + 3);
} else if (pConfig->hwm.hwmTempPar[i].Mode == BIT1) {
registerPM2RegF9 |= 1 << (i + 3);
}
}
WritePMIO2 (0xF8, AccWidthUint8, &registerPM2RegF8);
WritePMIO2 (0xF9, AccWidthUint8, &registerPM2RegF9);
}
/**
* hwmUpdateData - Hardware Monitor Update Data.
*
*
* @param[in] pConfig Southbridge configuration structure pointer.
*
*/
VOID
hwmUpdateData (
IN AMDSBCFG* pConfig
)
{
if ( pConfig->hwm.hwmEnable ) {
hwmSbtsiAutoPolling (pConfig);
hwmGetRawData (pConfig);
hwmCaculate (pConfig);
}
}
/**
* hwmCopyFanControl - Hardware Monitor Copy Fan Control Data.
*
*
* @param[in] pConfig Southbridge configuration structure pointer.
*
*/
VOID
hwmCopyFanControl (
IN AMDSBCFG* pConfig
)
{
UINT8 *fanControl;
UINT8 *fanControlCooked;
if ( pConfig->hwm.hwmEnable ) {
fanControl = & pConfig->hwm.hwmFanControl[0].InputControl_reg00;
fanControlCooked = & pConfig->hwm.hwmFanControlCooked[0].InputControl_reg00;
MemoryCopy (fanControlCooked, fanControl, (sizeof (HWM_fan_ctl_struct) * 5));
}
}
/**
* hwmInit - Init Hardware Monitor.
*
*
* @param[in] pConfig Southbridge configuration structure pointer.
*
*/
VOID
hwmInit (
IN AMDSBCFG* pConfig
)
{
hwmInitRegister (pConfig);
if ( pConfig->hwm.hwmEnable ) {
hwmCopyFanControl (pConfig);
hwmProcessParameter (pConfig);
hwmSetRegister (pConfig);
hwmSbtsiAutoPolling (pConfig);
}
}
//#endif