Nils Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 1 | /* |
| 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 Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 15 | */ |
| 16 | |
Li-Ta Lo | 71e3326 | 2006-03-13 22:20:29 +0000 | [diff] [blame] | 17 | #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 Lo | 71e3326 | 2006-03-13 22:20:29 +0000 | [diff] [blame] | 23 | /* spll_raw_clk = SYSREF * FbDIV, |
| 24 | * GLIU Clock = spll_raw_clk / MDIV |
Nils Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 25 | * CPU Clock = spll_raw_clk / VDIV |
Li-Ta Lo | 71e3326 | 2006-03-13 22:20:29 +0000 | [diff] [blame] | 26 | */ |
| 27 | |
| 28 | /* table for Feedback divisor to FbDiv register value */ |
| 29 | static 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 */ |
| 37 | static 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 Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 44 | /* 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 Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 53 | /* PLLCHECK_COMPLETED is the "we've already done this" flag */ |
Ronald G. Minnich | 6084160 | 2006-05-12 18:42:34 +0000 | [diff] [blame] | 54 | #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 Jacobs | 9644623 | 2010-11-01 14:39:49 +0000 | [diff] [blame] | 58 | #endif // RSTPPL_LOWER_BYPASS_SET |
Ronald G. Minnich | 6084160 | 2006-05-12 18:42:34 +0000 | [diff] [blame] | 59 | |
| 60 | #define DEFAULT_MDIV 3 |
| 61 | #define DEFAULT_VDIV 2 |
Ronald G. Minnich | 6084160 | 2006-05-12 18:42:34 +0000 | [diff] [blame] | 62 | |
| 63 | static void pll_reset(void) |
| 64 | { |
| 65 | msr_t msrGlcpSysRstpll; |
| 66 | unsigned MDIV_VDIV_FBDIV; |
Nils Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 67 | unsigned SyncBits; /* store the sync bits in up ebx */ |
Nils Jacobs | 76890dd | 2010-11-01 15:20:27 +0000 | [diff] [blame] | 68 | unsigned DEFAULT_FBDIV; |
| 69 | |
Nils Jacobs | eca3280 | 2010-11-05 00:23:11 +0000 | [diff] [blame] | 70 | if (CONFIG_GX2_PROCESSOR_MHZ == 400) { |
Nils Jacobs | 76890dd | 2010-11-01 15:20:27 +0000 | [diff] [blame] | 71 | DEFAULT_FBDIV = 24; |
Nils Jacobs | eca3280 | 2010-11-05 00:23:11 +0000 | [diff] [blame] | 72 | } else if (CONFIG_GX2_PROCESSOR_MHZ == 366) { |
Nils Jacobs | 76890dd | 2010-11-01 15:20:27 +0000 | [diff] [blame] | 73 | DEFAULT_FBDIV = 22; |
Nils Jacobs | eca3280 | 2010-11-05 00:23:11 +0000 | [diff] [blame] | 74 | } else if (CONFIG_GX2_PROCESSOR_MHZ == 300) { |
Nils Jacobs | 76890dd | 2010-11-01 15:20:27 +0000 | [diff] [blame] | 75 | DEFAULT_FBDIV = 18; |
| 76 | } else { |
Nils Jacobs | 76890dd | 2010-11-01 15:20:27 +0000 | [diff] [blame] | 77 | post_code(POST_PLL_CPU_VER_FAIL); |
Nils Jacobs | 8cf54c9 | 2010-12-30 19:21:08 +0000 | [diff] [blame] | 78 | die("Unsupported GX2_PROCESSOR_MHZ setting!\n"); |
Nils Jacobs | 76890dd | 2010-11-01 15:20:27 +0000 | [diff] [blame] | 79 | } |
Ronald G. Minnich | 6084160 | 2006-05-12 18:42:34 +0000 | [diff] [blame] | 80 | |
Nils Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 81 | /* clear the Bypass bit */ |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 82 | |
Nils Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 83 | /* 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 Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 85 | |
Ronald G. Minnich | 6084160 | 2006-05-12 18:42:34 +0000 | [diff] [blame] | 86 | msrGlcpSysRstpll = rdmsr(GLCP_SYS_RSTPLL); |
| 87 | msrGlcpSysRstpll.lo &= ~RSTPPL_LOWER_BYPASS_SET; |
| 88 | wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll); |
| 89 | |
Nils Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 90 | /* If the "we've already been here" flag is set, don't reconfigure the pll */ |
Ronald G. Minnich | 6084160 | 2006-05-12 18:42:34 +0000 | [diff] [blame] | 91 | if ( !(msrGlcpSysRstpll.lo & PLLCHECK_COMPLETED ) ) |
Nils Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 92 | { /* we haven't configured the PLL; do it now */ |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 93 | |
Nils Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 94 | /* 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 Reinauer | 0c781b2 | 2010-04-01 09:50:32 +0000 | [diff] [blame] | 96 | post_code(POST_PLL_INIT); |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 97 | |
Nils Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 98 | /* configure for DDR */ |
Ronald G. Minnich | 6084160 | 2006-05-12 18:42:34 +0000 | [diff] [blame] | 99 | msrGlcpSysRstpll.lo &= ~(1 << RSTPPL_LOWER_SDRMODE_SHIFT); |
| 100 | wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll); |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 101 | |
Nils Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 102 | /* Use Manual settings */ |
| 103 | /* UseManual: */ |
Stefan Reinauer | 0c781b2 | 2010-04-01 09:50:32 +0000 | [diff] [blame] | 104 | post_code(POST_PLL_MANUAL); |
Ronald G. Minnich | 6084160 | 2006-05-12 18:42:34 +0000 | [diff] [blame] | 105 | |
Nils Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 106 | /* 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 Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 109 | |
Nils Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 110 | /* ProgramClocks: */ |
| 111 | /* ax = VDIV, upper eax = MDIV, upper ecx = FbDIV */ |
| 112 | /* move everything into ebx */ |
| 113 | /* VDIV */ |
Ronald G. Minnich | 6084160 | 2006-05-12 18:42:34 +0000 | [diff] [blame] | 114 | MDIV_VDIV_FBDIV = ((DEFAULT_VDIV - 2) << RSTPLL_UPPER_VDIV_SHIFT); |
| 115 | |
Nils Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 116 | /* MDIV */ |
Ronald G. Minnich | 6084160 | 2006-05-12 18:42:34 +0000 | [diff] [blame] | 117 | MDIV_VDIV_FBDIV |= ((DEFAULT_MDIV - 2) << RSTPLL_UPPER_MDIV_SHIFT); |
| 118 | |
Nils Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 119 | /* FbDIV */ |
Ronald G. Minnich | 6084160 | 2006-05-12 18:42:34 +0000 | [diff] [blame] | 120 | MDIV_VDIV_FBDIV |= (plldiv2fbdiv[DEFAULT_FBDIV] << RSTPLL_UPPER_FBDIV_SHIFT); |
| 121 | |
Nils Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 122 | /* write GLCP_SYS_RSTPPL (GLCP reg 0x14) with clock values */ |
Ronald G. Minnich | 6084160 | 2006-05-12 18:42:34 +0000 | [diff] [blame] | 123 | 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 Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 129 | /* Set Reset, LockWait, and SW flag */ |
| 130 | /* DoReset: */ |
Ronald G. Minnich | 6084160 | 2006-05-12 18:42:34 +0000 | [diff] [blame] | 131 | |
Nils Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 132 | /* 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 Jacobs | 9644623 | 2010-11-01 14:39:49 +0000 | [diff] [blame] | 135 | SyncBits = 0; /* store the sync bits in up ebx */ |
Ronald G. Minnich | 6084160 | 2006-05-12 18:42:34 +0000 | [diff] [blame] | 136 | |
Nils Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 137 | /* Check for Bypass mode. */ |
Ronald G. Minnich | 6084160 | 2006-05-12 18:42:34 +0000 | [diff] [blame] | 138 | if (msrGlcpSysRstpll.lo & RSTPPL_LOWER_BYPASS_SET) |
| 139 | { |
Nils Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 140 | /* If we are in BYPASS PCI may or may not be sync'd but CPU and GeodeLink will. */ |
Ronald G. Minnich | 6084160 | 2006-05-12 18:42:34 +0000 | [diff] [blame] | 141 | SyncBits |= RSTPPL_LOWER_CPU_SEMI_SYNC_SET; |
| 142 | } |
| 143 | else |
| 144 | { |
Nils Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 145 | /* 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 Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 148 | if ( !(fbdiv2plldiv[((msrGlcpSysRstpll.hi >> RSTPLL_UPPER_FBDIV_SHIFT) & 0x3f)] % |
Ronald G. Minnich | 6084160 | 2006-05-12 18:42:34 +0000 | [diff] [blame] | 149 | (((msrGlcpSysRstpll.hi >> RSTPLL_UPPER_MDIV_SHIFT) & 0x0F) + 2)) ) |
| 150 | { |
| 151 | SyncBits |= RSTPPL_LOWER_PCI_SEMI_SYNC_SET; |
| 152 | } |
| 153 | |
Nils Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 154 | /* CheckCPUSync: */ |
| 155 | /* If Vdiv/Mdiv is evenly divisible then set the CPU semi-sync. */ |
| 156 | /* CPU is always greater or equal. */ |
Ronald G. Minnich | 6084160 | 2006-05-12 18:42:34 +0000 | [diff] [blame] | 157 | 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 Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 164 | /* SetSync: */ |
Ronald G. Minnich | 6084160 | 2006-05-12 18:42:34 +0000 | [diff] [blame] | 165 | 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 Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 168 | /* CheckSemiSync endp */ |
Ronald G. Minnich | 6084160 | 2006-05-12 18:42:34 +0000 | [diff] [blame] | 169 | |
Nils Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 170 | /* now we do the reset */ |
| 171 | /* Set hold count to 99 (063h) */ |
Ronald G. Minnich | 6084160 | 2006-05-12 18:42:34 +0000 | [diff] [blame] | 172 | 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 Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 177 | /* Don't want to use LOCKWAIT */ |
Ronald G. Minnich | 6084160 | 2006-05-12 18:42:34 +0000 | [diff] [blame] | 178 | 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 Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 181 | |
Nils Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 182 | /* You should never get here..... The chip has reset. */ |
Stefan Reinauer | 0c781b2 | 2010-04-01 09:50:32 +0000 | [diff] [blame] | 183 | post_code(POST_PLL_RESET_FAIL); |
Nils Jacobs | 8cf54c9 | 2010-12-30 19:21:08 +0000 | [diff] [blame] | 184 | die("CONFIGURING PLL FAILURE\n"); |
Ronald G. Minnich | 6084160 | 2006-05-12 18:42:34 +0000 | [diff] [blame] | 185 | |
Nils Jacobs | 809e29e | 2010-11-01 14:36:54 +0000 | [diff] [blame] | 186 | } /* we haven't configured the PLL; do it now */ |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 187 | |
Ronald G. Minnich | 6084160 | 2006-05-12 18:42:34 +0000 | [diff] [blame] | 188 | } |
Nils Jacobs | 76890dd | 2010-11-01 15:20:27 +0000 | [diff] [blame] | 189 | |
| 190 | static unsigned int GeodeLinkSpeed(void) |
| 191 | { |
| 192 | unsigned geodelinkspeed; |
Nils Jacobs | eca3280 | 2010-11-05 00:23:11 +0000 | [diff] [blame] | 193 | geodelinkspeed = ((CONFIG_GX2_PROCESSOR_MHZ * DEFAULT_VDIV) / DEFAULT_MDIV); |
Nils Jacobs | 76890dd | 2010-11-01 15:20:27 +0000 | [diff] [blame] | 194 | return (geodelinkspeed); |
| 195 | } |