From 065b7da298953feaec3563bf753f45cf00fba2c0 Mon Sep 17 00:00:00 2001 From: Alexandru Gagniuc <mr.nuke.me@gmail.com> Date: Tue, 15 Apr 2014 15:41:38 -0500 Subject: cpu/amd/agesa/family15tn: Add udelay implementation for SMM This is a small implementation which uses only MSRs and rdtsc, without relying on northbridge or other system hardware. It's SMM safe in that it only reads registers, and doesn't modify the state of the hardware. Change-Id: Ifa02ca73455b382f830c9b30b80b4f1bb18706b4 Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com> Reviewed-on: http://review.coreboot.org/5501 Tested-by: build bot (Jenkins) Reviewed-by: Aaron Durbin <adurbin@gmail.com> Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net> --- src/cpu/amd/agesa/family15tn/Makefile.inc | 2 ++ src/cpu/amd/agesa/family15tn/udelay.c | 45 +++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 src/cpu/amd/agesa/family15tn/udelay.c (limited to 'src/cpu/amd/agesa') diff --git a/src/cpu/amd/agesa/family15tn/Makefile.inc b/src/cpu/amd/agesa/family15tn/Makefile.inc index 19a2f0f298..a8f644d241 100644 --- a/src/cpu/amd/agesa/family15tn/Makefile.inc +++ b/src/cpu/amd/agesa/family15tn/Makefile.inc @@ -20,6 +20,8 @@ ramstage-y += chip_name.c ramstage-y += model_15_init.c +smm-$(CONFIG_HAVE_SMI_HANDLER) += udelay.c + subdirs-y += ../../mtrr subdirs-y += ../../smm subdirs-y += ../../../x86/tsc diff --git a/src/cpu/amd/agesa/family15tn/udelay.c b/src/cpu/amd/agesa/family15tn/udelay.c new file mode 100644 index 0000000000..5873237b0c --- /dev/null +++ b/src/cpu/amd/agesa/family15tn/udelay.c @@ -0,0 +1,45 @@ +/* + * udelay() impementation for SMI handlers + * This is neat in that it never writes to hardware registers, and thus does not + * modify the state of the hardware while servicing SMIs. + * + * Copyright (C) 2014 Alexandru Gagniuc <mr.nuke.me@gmail.com> + * Subject to the GNU GPL v2, or (at your option) any later version. + */ + +#include <cpu/x86/msr.h> +#include <cpu/x86/tsc.h> +#include <delay.h> +#include <stdint.h> + +void udelay(uint32_t us) +{ + uint8_t fid, did, pstate_idx; + uint64_t tsc_clock, tsc_start, tsc_now, tsc_wait_ticks; + msr_t msr; + const uint64_t tsc_base = 100000000; + + /* Get initial timestamp before we do the math */ + tsc_start = rdtscll(); + + /* Get the P-state. This determines which MSR to read */ + msr = rdmsr(0xc0010063); + pstate_idx = msr.lo & 0x07; + + /* Get FID and VID for current P-State */ + msr = rdmsr(0xc0010064 + pstate_idx); + + /* Extract the FID and VID values */ + fid = msr.lo & 0x3f; + did = (msr.lo >> 6) & 0x7; + + /* Calculate the CPU clock (from base freq of 100MHz) */ + tsc_clock = tsc_base * (fid + 0x10) / (1 << did); + + /* Now go on and wait */ + tsc_wait_ticks = (tsc_clock / 1000000) * us; + + do { + tsc_now = rdtscll(); + } while (tsc_now - tsc_wait_ticks < tsc_start); +} -- cgit v1.2.3