/** * @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, ®isterPM2RegF8); ReadPMIO2 (0xF9, AccWidthUint8, ®isterPM2RegF9); 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, ®isterPM2RegF8); WritePMIO2 (0xF9, AccWidthUint8, ®isterPM2RegF9); } /** * 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