blob: e599e00482290ef6ff3caee8d209b7648c2aaf6d [file] [log] [blame]
Martin Roth58562402015-10-11 10:36:26 +02001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2007-2008 coresystems GmbH
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Martin Roth58562402015-10-11 10:36:26 +020014 */
15
16#include <delay.h>
17#include <stdint.h>
18#include <cpu/x86/tsc.h>
19#include <cpu/x86/msr.h>
20
21/**
22 * Intel Rangeley CPUs always run the TSC at BCLK=100MHz
23 */
24
25/* Simple 32- to 64-bit multiplication. Uses 16-bit words to avoid overflow.
26 * This code is used to prevent use of libgcc's umoddi3.
27 */
28static inline void multiply_to_tsc(tsc_t *const tsc, const u32 a, const u32 b)
29{
30 tsc->lo = (a & 0xffff) * (b & 0xffff);
31 tsc->hi = ((tsc->lo >> 16)
32 + ((a & 0xffff) * (b >> 16))
33 + ((b & 0xffff) * (a >> 16)));
34 tsc->lo = ((tsc->hi & 0xffff) << 16) | (tsc->lo & 0xffff);
35 tsc->hi = ((a >> 16) * (b >> 16)) + (tsc->hi >> 16);
36}
37
38void udelay(u32 us)
39{
40 u32 dword;
41 tsc_t tsc, tsc1, tscd;
42 msr_t msr;
43 u32 fsb = 100, divisor;
44 u32 d; /* ticks per us */
45
46 msr = rdmsr(0xce);
47 divisor = (msr.lo >> 8) & 0xff;
48
49 d = fsb * divisor;
50 multiply_to_tsc(&tscd, us, d);
51
52 tsc1 = rdtsc();
53 dword = tsc1.lo + tscd.lo;
54 if ((dword < tsc1.lo) || (dword < tscd.lo)) {
55 tsc1.hi++;
56 }
57 tsc1.lo = dword;
58 tsc1.hi += tscd.hi;
59
60 do {
61 tsc = rdtsc();
62 } while ((tsc.hi < tsc1.hi)
63 || ((tsc.hi == tsc1.hi) && (tsc.lo <= tsc1.lo)));
64}