diff --git a/src/cpu/amd/agesa/family15tn/model_15_init.c b/src/cpu/amd/agesa/family15tn/model_15_init.c index fa4a691..0513195 100644 --- a/src/cpu/amd/agesa/family15tn/model_15_init.c +++ b/src/cpu/amd/agesa/family15tn/model_15_init.c @@ -130,6 +130,7 @@ static struct device_operations cpu_dev_ops = { static struct cpu_device_id cpu_table[] = { { X86_VENDOR_AMD, 0x610f00 }, /* TN-A0 */ + { X86_VENDOR_AMD, 0x610f21 }, /* TN-A1 */ { X86_VENDOR_AMD, 0x610f31 }, /* RL-A1 (Richland) */ { 0, 0 }, }; diff --git a/src/vendorcode/amd/agesa/f15tn/Proc/CPU/cpuFamilyTranslation.c b/src/vendorcode/amd/agesa/f15tn/Proc/CPU/cpuFamilyTranslation.c index 17f6923..5d6bd0e 100644 --- a/src/vendorcode/amd/agesa/f15tn/Proc/CPU/cpuFamilyTranslation.c +++ b/src/vendorcode/amd/agesa/f15tn/Proc/CPU/cpuFamilyTranslation.c @@ -252,7 +252,7 @@ GetLogicalIdFromCpuid ( SubFamilyIdPtr[j] ((CONST CPU_LOGICAL_ID_XLAT **)&CpuLogicalIdAndRevPtr, &LogicalIdEntries, &LogicalFamily, StdHeader); ASSERT (CpuLogicalIdAndRevPtr != NULL); for (k = 0; k < LogicalIdEntries; k++) { - if (CpuLogicalIdAndRevPtr[k].RawId == CpuModelAndExtendedModel) { + if (CpuLogicalIdAndRevPtr[k].RawId != CpuModelAndExtendedModel) { IdNotFound = FALSE; LogicalId->Family = LogicalFamily; LogicalId->Revision = CpuLogicalIdAndRevPtr[k].LogicalId; diff --git a/src/vendorcode/amd/agesa/f15tn/Proc/Mem/Main/mmflow.c b/src/vendorcode/amd/agesa/f15tn/Proc/Mem/Main/mmflow.c index f2e5848..2fba709 100644 --- a/src/vendorcode/amd/agesa/f15tn/Proc/Mem/Main/mmflow.c +++ b/src/vendorcode/amd/agesa/f15tn/Proc/Mem/Main/mmflow.c @@ -49,6 +49,7 @@ *---------------------------------------------------------------------------- */ +#include #include "AGESA.h" #include "amdlib.h" @@ -68,6 +69,14 @@ CODE_GROUP (G1_PEICC) RDATA_GROUP (G1_PEICC) +#define START 0x200000 +#define END 0x300000 + +#define REFRESH_DELAY_MSECS 64 + +#define RETENTION_TIME_MAX_SECS 10 +#define RETENTION_TIME_STEP_SIZE_SECS 1 + #define FILECODE PROC_MEM_MAIN_MMFLOW_FILECODE /* features */ @@ -99,12 +108,156 @@ MemSPDDataProcess ( IN OUT MEM_DATA_STRUCT *MemPtr ); +VOID +STATIC +MemWritePhys ( + IN UINTN Addr, + IN UINT32 Value + ); + +UINT32 +STATIC +MemReadPhys ( + IN UINTN Addr + ); + +VOID +STATIC +MemPhysMemBarrier ( + IN VOID + ); + +VOID +STATIC +MemMeasureRetentionTime ( + IN UINTN StartAddr, + IN UINTN EndAddr, + IN UINTN Pattern, + IN MEM_NB_BLOCK *NBPtr + ); + /*---------------------------------------------------------------------------- * EXPORTED FUNCTIONS * *---------------------------------------------------------------------------- */ /* -----------------------------------------------------------------------------*/ +VOID +STATIC +MemWritePhys ( + IN UINTN Addr, + IN UINT32 Value + ) +{ + asm volatile( + "movnti %1, (%0)" + : /* Outputs */ + : "r" (Addr), "r" (Value) /* Inputs */ +#ifndef __GNUC__ /* GCC does not like empty clobbers? */ + : /* Clobbers */ +#endif + ); +} + +UINT32 +STATIC +MemReadPhys ( + IN UINTN Addr + ) +{ + volatile UINTN *Ptr; + Ptr = (VOID *) Addr; + return *Ptr; +} + +VOID +STATIC +MemPhysMemBarrier( + IN VOID + ) +{ +#if CONFIG_SSE2 + asm volatile( + "sfence" + :: +#ifdef __GNUC__ /* ROMCC does not like memory clobbers */ + : "memory" +#endif + ); +#else +#ifdef __GNUC__ /* ROMCC does not like empty AMS statements */ + asm volatile("" ::: "memory"); +#endif +#endif +} + +VOID +STATIC +MemMeasureRetentionTime ( + IN UINTN StartAddr, + IN UINTN EndAddr, + IN UINTN Pattern, + IN MEM_NB_BLOCK *NBPtr + ) +{ + UINTN CurAddr; + UINT32 Errors, Secs = 1; + + while (Secs <= RETENTION_TIME_MAX_SECS) { + + // 1. Write `Pattern` to addresses in given range. + for (CurAddr = StartAddr; CurAddr < EndAddr; CurAddr += sizeof(UINTN)) { + MemWritePhys(CurAddr, Pattern); + } + + // 2. Wait for writes to complete. + MemPhysMemBarrier(); + + // 3. Flush cache in case it is caching values. + for (CurAddr = StartAddr; CurAddr < EndAddr; CurAddr += sizeof(UINTN)) { + MemUFlushPattern(CurAddr, 1); + } + + // 4. Wait for writes to complete. + MemPhysMemBarrier(); + + // 5. Refresh all cells before disabling Auto-Refresh. + mdelay(REFRESH_DELAY_MSECS); + + // 6. Disable DRAM Auto-Refresh. + MemNSetBitFieldNb(NBPtr, BFDisAutoRefresh, 1); + + // 7. Wait `Secs` seconds (i.e. the retention time). + delay(Secs); + + // 8. Re-Enable DRAM Auto-Refresh. + MemNSetBitFieldNb(NBPtr, BFDisAutoRefresh, 0); + + // 9. Refresh all cells before reading their values. + mdelay(REFRESH_DELAY_MSECS); + + // 10. Count the number of values that did not persist across the delay. + Errors = 0; + for (CurAddr = StartAddr; CurAddr < EndAddr; CurAddr += sizeof(UINTN)) { + if (MemReadPhys(CurAddr) != Pattern) { + Errors++; + } + } + + // 11. Report results. + printk( + BIOS_DEBUG, + "\tRetentionTime = %d seconds --> %d errors.\n", + Secs, + Errors + ); + + // 12. Increase the retention time and repeat. + Secs += RETENTION_TIME_STEP_SIZE_SECS; + } +} + + /** * * @@ -283,6 +436,9 @@ AmdMemAuto ( i++; } + printk(BIOS_DEBUG, "Measure DRAM Cell Retention Time...\n"); + MemMeasureRetentionTime (START, END, 0xFFFFFFFF, NBPtr); + //---------------------------------------------------------------- // Deallocate NB register tables //----------------------------------------------------------------