blob: 303d64a108b92eb7a729c3e9590770a945ebd026 [file] [log] [blame]
Nils Jacobs809e29e2010-11-01 14:36:54 +00001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2007 Advanced Micro Devices, Inc.
5 * Copyright (C) 2010 Nils Jacobs
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Nils Jacobs809e29e2010-11-01 14:36:54 +000015 */
16
Li-Ta Lo71e33262006-03-13 22:20:29 +000017#include <cpu/x86/tsc.h>
18
19#define CLOCK_TICK_RATE 1193180U /* Underlying HZ */
20#define CALIBRATE_INTERVAL ((20*CLOCK_TICK_RATE)/1000) /* 20ms */
21#define CALIBRATE_DIVISOR (20*1000) /* 20ms / 20000 == 1usec */
22
Li-Ta Lo71e33262006-03-13 22:20:29 +000023/* spll_raw_clk = SYSREF * FbDIV,
24 * GLIU Clock = spll_raw_clk / MDIV
Nils Jacobs809e29e2010-11-01 14:36:54 +000025 * CPU Clock = spll_raw_clk / VDIV
Li-Ta Lo71e33262006-03-13 22:20:29 +000026 */
27
28/* table for Feedback divisor to FbDiv register value */
29static const unsigned char plldiv2fbdiv[] = {
30 0, 0, 0, 0, 0, 0, 15, 7, 3, 1, 0, 32, 16, 40, 20, 42, /* pll div 0 - 15 */
31 21, 10, 37, 50, 25, 12, 38, 19, 9, 4, 34, 17, 8, 36, 18, 41, /* pll div 16 - 31 */
32 52, 26, 45, 54, 27, 13, 6, 35, 49, 56, 28, 46, 23, 11, 05, 02, /* pll div 32 - 47 */
33 33, 48, 24, 44, 22, 43, 53, 58, 29, 14, 39, 51, 57, 60, 30, 47, /* pll div 48 - 63 */
34};
35
36/* table for FbDiv register value to Feedback divisor */
37static const unsigned char fbdiv2plldiv[] = {
38 10, 9, 47, 8, 25, 46, 38, 7, 28, 24, 17, 45, 21, 37, 57, 6,
39 12, 27, 30, 23, 14, 16, 52, 44, 50, 20, 33, 36, 42, 56, 0, 0,
40 11, 48, 26, 39, 29, 18, 22, 58, 13, 31, 15, 53, 51, 34, 43, 0,
41 49, 40, 19, 59, 32, 54, 35, 0, 41, 60, 55, 0, 61, 0, 0, 0
42};
43
Nils Jacobs809e29e2010-11-01 14:36:54 +000044/* FbDIV VDIV MDIV CPU/GeodeLink */
45/* 12 2 3 200/133 */
46/* 16 2 3 266/177 */
47/* 18 2 3 300/200 */
48/* 20 2 3 333/222 */
49/* 22 2 3 366/244 */
50/* 24 2 3 400/266 */
51/* 26 2 3 433/289 */
52
Nils Jacobs809e29e2010-11-01 14:36:54 +000053/* PLLCHECK_COMPLETED is the "we've already done this" flag */
Ronald G. Minnich60841602006-05-12 18:42:34 +000054#define PLLCHECK_COMPLETED (1 << RSTPLL_LOWER_SWFLAGS_SHIFT)
55
56#ifndef RSTPPL_LOWER_BYPASS_SET
57#define RSTPPL_LOWER_BYPASS_SET (1 << GLCP_SYS_RSTPLL_BYPASS)
Nils Jacobs96446232010-11-01 14:39:49 +000058#endif // RSTPPL_LOWER_BYPASS_SET
Ronald G. Minnich60841602006-05-12 18:42:34 +000059
60#define DEFAULT_MDIV 3
61#define DEFAULT_VDIV 2
Ronald G. Minnich60841602006-05-12 18:42:34 +000062
63static void pll_reset(void)
64{
65 msr_t msrGlcpSysRstpll;
66 unsigned MDIV_VDIV_FBDIV;
Nils Jacobs809e29e2010-11-01 14:36:54 +000067 unsigned SyncBits; /* store the sync bits in up ebx */
Nils Jacobs76890dd2010-11-01 15:20:27 +000068 unsigned DEFAULT_FBDIV;
69
Nils Jacobseca32802010-11-05 00:23:11 +000070 if (CONFIG_GX2_PROCESSOR_MHZ == 400) {
Nils Jacobs76890dd2010-11-01 15:20:27 +000071 DEFAULT_FBDIV = 24;
Nils Jacobseca32802010-11-05 00:23:11 +000072 } else if (CONFIG_GX2_PROCESSOR_MHZ == 366) {
Nils Jacobs76890dd2010-11-01 15:20:27 +000073 DEFAULT_FBDIV = 22;
Nils Jacobseca32802010-11-05 00:23:11 +000074 } else if (CONFIG_GX2_PROCESSOR_MHZ == 300) {
Nils Jacobs76890dd2010-11-01 15:20:27 +000075 DEFAULT_FBDIV = 18;
76 } else {
Nils Jacobs76890dd2010-11-01 15:20:27 +000077 post_code(POST_PLL_CPU_VER_FAIL);
Nils Jacobs8cf54c92010-12-30 19:21:08 +000078 die("Unsupported GX2_PROCESSOR_MHZ setting!\n");
Nils Jacobs76890dd2010-11-01 15:20:27 +000079 }
Ronald G. Minnich60841602006-05-12 18:42:34 +000080
Nils Jacobs809e29e2010-11-01 14:36:54 +000081 /* clear the Bypass bit */
Stefan Reinauer14e22772010-04-27 06:56:47 +000082
Nils Jacobs809e29e2010-11-01 14:36:54 +000083 /* If the straps say we are in bypass and the syspll is not AND there are no software */
84 /* bits set then FS2 or something set up the PLL and we should not change it. */
Stefan Reinauer14e22772010-04-27 06:56:47 +000085
Ronald G. Minnich60841602006-05-12 18:42:34 +000086 msrGlcpSysRstpll = rdmsr(GLCP_SYS_RSTPLL);
87 msrGlcpSysRstpll.lo &= ~RSTPPL_LOWER_BYPASS_SET;
88 wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll);
89
Nils Jacobs809e29e2010-11-01 14:36:54 +000090 /* If the "we've already been here" flag is set, don't reconfigure the pll */
Ronald G. Minnich60841602006-05-12 18:42:34 +000091 if ( !(msrGlcpSysRstpll.lo & PLLCHECK_COMPLETED ) )
Nils Jacobs809e29e2010-11-01 14:36:54 +000092 { /* we haven't configured the PLL; do it now */
Stefan Reinauer14e22772010-04-27 06:56:47 +000093
Nils Jacobs809e29e2010-11-01 14:36:54 +000094 /* Store PCI33(0)/66(1), SDR(0)/DDR(1), and CRT(0)/TFT(1) in upper esi to get to the */
95 /* correct Strap Table. */
Stefan Reinauer0c781b22010-04-01 09:50:32 +000096 post_code(POST_PLL_INIT);
Stefan Reinauer14e22772010-04-27 06:56:47 +000097
Nils Jacobs809e29e2010-11-01 14:36:54 +000098 /* configure for DDR */
Ronald G. Minnich60841602006-05-12 18:42:34 +000099 msrGlcpSysRstpll.lo &= ~(1 << RSTPPL_LOWER_SDRMODE_SHIFT);
100 wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000101
Nils Jacobs809e29e2010-11-01 14:36:54 +0000102 /* Use Manual settings */
103 /* UseManual: */
Stefan Reinauer0c781b22010-04-01 09:50:32 +0000104 post_code(POST_PLL_MANUAL);
Ronald G. Minnich60841602006-05-12 18:42:34 +0000105
Nils Jacobs809e29e2010-11-01 14:36:54 +0000106 /* DIV settings manually entered. */
107 /* ax = VDIV, upper eax = MDIV, upper ecx = FbDIV */
108 /* use gs and fs since we don't need them. */
Stefan Reinauer14e22772010-04-27 06:56:47 +0000109
Nils Jacobs809e29e2010-11-01 14:36:54 +0000110 /* ProgramClocks: */
111 /* ax = VDIV, upper eax = MDIV, upper ecx = FbDIV */
112 /* move everything into ebx */
113 /* VDIV */
Ronald G. Minnich60841602006-05-12 18:42:34 +0000114 MDIV_VDIV_FBDIV = ((DEFAULT_VDIV - 2) << RSTPLL_UPPER_VDIV_SHIFT);
115
Nils Jacobs809e29e2010-11-01 14:36:54 +0000116 /* MDIV */
Ronald G. Minnich60841602006-05-12 18:42:34 +0000117 MDIV_VDIV_FBDIV |= ((DEFAULT_MDIV - 2) << RSTPLL_UPPER_MDIV_SHIFT);
118
Nils Jacobs809e29e2010-11-01 14:36:54 +0000119 /* FbDIV */
Ronald G. Minnich60841602006-05-12 18:42:34 +0000120 MDIV_VDIV_FBDIV |= (plldiv2fbdiv[DEFAULT_FBDIV] << RSTPLL_UPPER_FBDIV_SHIFT);
121
Nils Jacobs809e29e2010-11-01 14:36:54 +0000122 /* write GLCP_SYS_RSTPPL (GLCP reg 0x14) with clock values */
Ronald G. Minnich60841602006-05-12 18:42:34 +0000123 msrGlcpSysRstpll.lo &= ~(1 << RSTPPL_LOWER_SDRMODE_SHIFT);
124 wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll);
125
126 msrGlcpSysRstpll.hi = MDIV_VDIV_FBDIV;
127 wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll);
128
Nils Jacobs809e29e2010-11-01 14:36:54 +0000129 /* Set Reset, LockWait, and SW flag */
130 /* DoReset: */
Ronald G. Minnich60841602006-05-12 18:42:34 +0000131
Nils Jacobs809e29e2010-11-01 14:36:54 +0000132 /* CheckSemiSync proc */
133 /* Check for Semi-Sync in GeodeLink and CPU. */
134 /* We need to do this here since the strap settings don't account for these bits. */
Nils Jacobs96446232010-11-01 14:39:49 +0000135 SyncBits = 0; /* store the sync bits in up ebx */
Ronald G. Minnich60841602006-05-12 18:42:34 +0000136
Nils Jacobs809e29e2010-11-01 14:36:54 +0000137 /* Check for Bypass mode. */
Ronald G. Minnich60841602006-05-12 18:42:34 +0000138 if (msrGlcpSysRstpll.lo & RSTPPL_LOWER_BYPASS_SET)
139 {
Nils Jacobs809e29e2010-11-01 14:36:54 +0000140 /* If we are in BYPASS PCI may or may not be sync'd but CPU and GeodeLink will. */
Ronald G. Minnich60841602006-05-12 18:42:34 +0000141 SyncBits |= RSTPPL_LOWER_CPU_SEMI_SYNC_SET;
142 }
143 else
144 {
Nils Jacobs809e29e2010-11-01 14:36:54 +0000145 /* CheckPCIsync: */
146 /* If FBdiv/Mdiv is evenly divisible then set the PCI semi-sync. FB is always greater */
147 /* look up the real divider... if we get a 0 we have serious problems */
Stefan Reinauer14e22772010-04-27 06:56:47 +0000148 if ( !(fbdiv2plldiv[((msrGlcpSysRstpll.hi >> RSTPLL_UPPER_FBDIV_SHIFT) & 0x3f)] %
Ronald G. Minnich60841602006-05-12 18:42:34 +0000149 (((msrGlcpSysRstpll.hi >> RSTPLL_UPPER_MDIV_SHIFT) & 0x0F) + 2)) )
150 {
151 SyncBits |= RSTPPL_LOWER_PCI_SEMI_SYNC_SET;
152 }
153
Nils Jacobs809e29e2010-11-01 14:36:54 +0000154 /* CheckCPUSync: */
155 /* If Vdiv/Mdiv is evenly divisible then set the CPU semi-sync. */
156 /* CPU is always greater or equal. */
Ronald G. Minnich60841602006-05-12 18:42:34 +0000157 if (!((((msrGlcpSysRstpll.hi >> RSTPLL_UPPER_MDIV_SHIFT) & 0x07) + 2) %
158 (((msrGlcpSysRstpll.hi >> RSTPLL_UPPER_VDIV_SHIFT) & 0x0F) + 2)))
159 {
160 SyncBits |= RSTPPL_LOWER_CPU_SEMI_SYNC_SET;
161 }
162 }
163
Nils Jacobs809e29e2010-11-01 14:36:54 +0000164 /* SetSync: */
Ronald G. Minnich60841602006-05-12 18:42:34 +0000165 msrGlcpSysRstpll.lo &= ~(RSTPPL_LOWER_PCI_SEMI_SYNC_SET | RSTPPL_LOWER_CPU_SEMI_SYNC_SET);
166 msrGlcpSysRstpll.lo |= SyncBits;
167 wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll);
Nils Jacobs809e29e2010-11-01 14:36:54 +0000168 /* CheckSemiSync endp */
Ronald G. Minnich60841602006-05-12 18:42:34 +0000169
Nils Jacobs809e29e2010-11-01 14:36:54 +0000170 /* now we do the reset */
171 /* Set hold count to 99 (063h) */
Ronald G. Minnich60841602006-05-12 18:42:34 +0000172 msrGlcpSysRstpll.lo &= ~(0x0FF << RSTPPL_LOWER_HOLD_COUNT_SHIFT);
173 msrGlcpSysRstpll.lo |= (0x0DE << RSTPPL_LOWER_HOLD_COUNT_SHIFT);
174 msrGlcpSysRstpll.lo |= PLLCHECK_COMPLETED; // Say we are done
175 wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll);
176
Nils Jacobs809e29e2010-11-01 14:36:54 +0000177 /* Don't want to use LOCKWAIT */
Ronald G. Minnich60841602006-05-12 18:42:34 +0000178 msrGlcpSysRstpll.lo |= (RSTPPL_LOWER_PLL_RESET_SET + RSTPPL_LOWER_PD_SET);
179 msrGlcpSysRstpll.lo |= RSTPPL_LOWER_CHIP_RESET_SET;
180 wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000181
Nils Jacobs809e29e2010-11-01 14:36:54 +0000182 /* You should never get here..... The chip has reset. */
Stefan Reinauer0c781b22010-04-01 09:50:32 +0000183 post_code(POST_PLL_RESET_FAIL);
Nils Jacobs8cf54c92010-12-30 19:21:08 +0000184 die("CONFIGURING PLL FAILURE\n");
Ronald G. Minnich60841602006-05-12 18:42:34 +0000185
Nils Jacobs809e29e2010-11-01 14:36:54 +0000186 } /* we haven't configured the PLL; do it now */
Stefan Reinauer14e22772010-04-27 06:56:47 +0000187
Ronald G. Minnich60841602006-05-12 18:42:34 +0000188}
Nils Jacobs76890dd2010-11-01 15:20:27 +0000189
190static unsigned int GeodeLinkSpeed(void)
191{
192 unsigned geodelinkspeed;
Nils Jacobseca32802010-11-05 00:23:11 +0000193 geodelinkspeed = ((CONFIG_GX2_PROCESSOR_MHZ * DEFAULT_VDIV) / DEFAULT_MDIV);
Nils Jacobs76890dd2010-11-01 15:20:27 +0000194 return (geodelinkspeed);
195}