blob: ad2e5431751106c6954c1ce8af8a3a60120ccb7f [file] [log] [blame]
Patrick Georgi2efc8802012-11-06 11:03:53 +01001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2007-2008 coresystems GmbH
Patrick Georgi2efc8802012-11-06 11:03:53 +01005 *
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.
Patrick Georgi2efc8802012-11-06 11:03:53 +010014 */
15
16#include <stdint.h>
17#include <cpu/x86/tsc.h>
18#include <cpu/x86/msr.h>
Patrick Georgi8cc84682013-02-09 15:56:04 +010019#include <cpu/intel/speedstep.h>
Patrick Georgi2efc8802012-11-06 11:03:53 +010020#include "delay.h"
21
Patrick Georgi2efc8802012-11-06 11:03:53 +010022/**
Paul Menzelabe68472013-05-08 17:08:55 +020023 * Intel Core(tm) CPUs always run the TSC at the maximum possible CPU clock
Patrick Georgi2efc8802012-11-06 11:03:53 +010024 */
25static void _udelay(const u32 us, const u32 numerator, const int total)
26{
27 u32 dword;
28 tsc_t tsc, tsc1, tscd;
29 msr_t msr;
30 u32 fsb = 0, divisor;
31 u32 d; /* ticks per us */
32
Patrick Georgi8cc84682013-02-09 15:56:04 +010033 msr = rdmsr(MSR_FSB_FREQ);
Patrick Georgi2efc8802012-11-06 11:03:53 +010034 switch (msr.lo & 0x07) {
35 case 5:
36 fsb = 400;
37 break;
38 case 1:
39 fsb = 533;
40 break;
41 case 3:
42 fsb = 667;
43 break;
44 case 2:
45 fsb = 800;
46 break;
47 case 0:
48 fsb = 1067;
49 break;
50 case 4:
51 fsb = 1333;
52 break;
53 case 6:
54 fsb = 1600;
55 break;
56 }
57
58 msr = rdmsr(0x198);
59 divisor = (msr.hi >> 8) & 0x1f;
60
Paul Menzelabe68472013-05-08 17:08:55 +020061 d = ((fsb * divisor) / numerator) / 4; /* CPU clock is always a quarter. */
Patrick Georgi2efc8802012-11-06 11:03:53 +010062
63 multiply_to_tsc(&tscd, us, d);
64
65 if (!total) {
66 tsc1 = rdtsc();
67 dword = tsc1.lo + tscd.lo;
68 if ((dword < tsc1.lo) || (dword < tscd.lo)) {
69 tsc1.hi++;
70 }
71 tsc1.lo = dword;
72 tsc1.hi += tscd.hi;
73 } else {
74 tsc1 = tscd;
75 }
76
77 do {
78 tsc = rdtsc();
79 } while ((tsc.hi < tsc1.hi)
80 || ((tsc.hi == tsc1.hi) && (tsc.lo < tsc1.lo)));
81}
82
83void udelay(const u32 us)
84{
85 _udelay(us, 1, 0);
86}
87
88void ns100delay(const u32 ns100)
89{
90 _udelay(ns100, 10, 0);
91}
92
93void udelay_from_reset(const u32 us)
94{
95 _udelay(us, 1, 1);
96}