898e31dcd4a30b7addffd3926057820f8fa173d3
[coreboot.git] / src / northbridge / amd / gx2 / pll_reset.c
1 #include <cpu/x86/tsc.h>
2
3 #define CLOCK_TICK_RATE 1193180U /* Underlying HZ */
4 #define CALIBRATE_INTERVAL ((20*CLOCK_TICK_RATE)/1000) /* 20ms */
5 #define CALIBRATE_DIVISOR  (20*1000) /* 20ms / 20000 == 1usec */
6
7 static unsigned int calibrate_tsc(void)
8 {
9         /* Set the Gate high, disable speaker */
10         outb((inb(0x61) & ~0x02) | 0x01, 0x61);
11
12         /*
13          * Now let's take care of CTC channel 2
14          *
15          * Set the Gate high, program CTC channel 2 for mode 0,
16          * (interrupt on terminal count mode), binary count,
17          * load 5 * LATCH count, (LSB and MSB) to begin countdown.
18          */
19         outb(0xb0, 0x43);                       /* binary, mode 0, LSB/MSB, Ch 2 */
20         outb(CALIBRATE_INTERVAL & 0xff, 0x42);  /* LSB of count */
21         outb(CALIBRATE_INTERVAL >> 8, 0x42);    /* MSB of count */
22
23         {
24                 tsc_t start;
25                 tsc_t end;
26                 unsigned long count;
27
28                 start = rdtsc();
29                 count = 0;
30                 do {
31                         count++;
32                 } while ((inb(0x61) & 0x20) == 0);
33                 end = rdtsc();
34
35                 /* Error: ECTCNEVERSET */
36                 if (count <= 1)
37                         goto bad_ctc;
38
39                 /* 64-bit subtract - gcc just messes up with long longs */
40                 __asm__("subl %2,%0\n\t"
41                         "sbbl %3,%1"
42                         :"=a" (end.lo), "=d" (end.hi)
43                         :"g" (start.lo), "g" (start.hi),
44                          "0" (end.lo), "1" (end.hi));
45
46                 /* Error: ECPUTOOFAST */
47                 if (end.hi)
48                         goto bad_ctc;
49
50
51                 /* Error: ECPUTOOSLOW */
52                 if (end.lo <= CALIBRATE_DIVISOR)
53                         goto bad_ctc;
54
55                 return (end.lo + CALIBRATE_DIVISOR -1)/CALIBRATE_DIVISOR;
56         }
57
58         /*
59          * The CTC wasn't reliable: we got a hit on the very first read,
60          * or the CPU was so fast/slow that the quotient wouldn't fit in
61          * 32 bits..
62          */
63 bad_ctc:
64         print_err("bad_ctc\n");
65         return 0;
66 }
67
68 /* spll_raw_clk = SYSREF * FbDIV,
69  * GLIU Clock   = spll_raw_clk / MDIV
70  * CPU Clock    = sppl_raw_clk / VDIV
71  */
72
73 /* table for Feedback divisor to FbDiv register value */
74 static const unsigned char plldiv2fbdiv[] = {
75          0,  0,  0,  0,  0,  0, 15,  7,  3,  1,  0, 32, 16, 40, 20, 42, /* pll div  0 - 15 */
76         21, 10, 37, 50, 25, 12, 38, 19,  9,  4, 34, 17,  8, 36, 18, 41, /* pll div 16 - 31 */
77         52, 26, 45, 54, 27, 13,  6, 35, 49, 56, 28, 46, 23, 11, 05, 02, /* pll div 32 - 47 */
78         33, 48, 24, 44, 22, 43, 53, 58, 29, 14, 39, 51, 57, 60, 30, 47, /* pll div 48 - 63 */
79 };
80
81 /* table for FbDiv register value to Feedback divisor */
82 static const unsigned char fbdiv2plldiv[] = {
83         10,  9, 47,  8, 25, 46, 38,  7, 28, 24, 17, 45, 21, 37, 57,  6,
84         12, 27, 30, 23, 14, 16, 52, 44, 50, 20, 33, 36, 42, 56,  0,  0,
85         11, 48, 26, 39, 29, 18, 22, 58, 13, 31, 15, 53, 51, 34, 43,  0,
86         49, 40, 19, 59, 32, 54, 35,  0, 41, 60, 55,  0, 61,  0,  0,  0
87 };
88
89 static const unsigned char pci33_ddr_crt [] = {
90         /* FbDIV, VDIV, MDIV               CPU/GeodeLink */
91              12,    2,    3,            // 200/133
92              16,    2,    3,            // 266/177
93              18,    2,    3,            // 300/200
94              20,    2,    3,            // 333/222
95              22,    2,    3,            // 366/244
96              24,    2,    3,            // 400/266
97              26,    2,    3             // 433/289
98 };
99
100 #if 0
101 static unsigned int get_memory_speed(void)
102 {
103         unsigned char val, hi, lo;
104
105         val = spd_read_byte(0xA0, 9);
106         hi = (val >> 4) & 0x0f;
107         lo = val & 0x0f;
108
109         return 20000/(hi*10 + lo);
110 }
111 #endif
112
113 #define USE_GOODRICH_VERSION 1
114
115 #if USE_GOODRICH_VERSION
116 ///////////////////////////////////////////////////////////////////////////////
117 // Goodrich Version of pll_reset
118
119 // PLLCHECK_COMPLETED is the "we've already done this" flag
120 #define PLLCHECK_COMPLETED (1 << RSTPLL_LOWER_SWFLAGS_SHIFT)
121
122 #ifndef RSTPPL_LOWER_BYPASS_SET
123 #define RSTPPL_LOWER_BYPASS_SET (1 << GLCP_SYS_RSTPLL_BYPASS)
124 #endif // RSTPPL_LOWER_BYPASS_SET
125
126 #define DEFAULT_MDIV    3
127 #define DEFAULT_VDIV    2
128 #define DEFAULT_FBDIV   22      // 366/244 ; 24 400/266 018 ;300/200 
129
130 static void pll_reset(void)
131 {
132         msr_t msrGlcpSysRstpll;
133         unsigned MDIV_VDIV_FBDIV;
134         unsigned SyncBits;                      // store the sync bits in up ebx
135
136         // clear the Bypass bit
137         
138         // If the straps say we are in bypass and the syspll is not AND there are no software
139         // bits set then FS2 or something set up the PLL and we should not change it.
140         
141         msrGlcpSysRstpll = rdmsr(GLCP_SYS_RSTPLL);
142         msrGlcpSysRstpll.lo &= ~RSTPPL_LOWER_BYPASS_SET;
143         wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll);
144
145         // If the "we've already been here" flag is set, don't reconfigure the pll
146         if ( !(msrGlcpSysRstpll.lo & PLLCHECK_COMPLETED ) )
147         { // we haven't configured the PLL; do it now
148         
149                 // Store PCI33(0)/66(1), SDR(0)/DDR(1), and CRT(0)/TFT(1) in upper esi to get to the
150                 // correct Strap Table.
151                 post_code(POST_PLL_INIT);
152                 
153                 // configure for DDR
154                 msrGlcpSysRstpll.lo &= ~(1 << RSTPPL_LOWER_SDRMODE_SHIFT);
155                 wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll);
156                 
157                 // Use Manual settings
158                 //      UseManual:
159                 post_code(POST_PLL_MANUAL);
160
161                 // DIV settings manually entered.
162                 // ax = VDIV, upper eax = MDIV, upper ecx = FbDIV
163                 // use gs and fs since we don't need them.
164                 
165                 //      ProgramClocks:
166                 // ax = VDIV, upper eax = MDIV, upper ecx = FbDIV
167                 // move everything into ebx
168                 // VDIV
169                 MDIV_VDIV_FBDIV = ((DEFAULT_VDIV - 2) << RSTPLL_UPPER_VDIV_SHIFT);
170
171                 // MDIV
172                 MDIV_VDIV_FBDIV |= ((DEFAULT_MDIV - 2) << RSTPLL_UPPER_MDIV_SHIFT);
173
174                 // FbDIV
175                 MDIV_VDIV_FBDIV |= (plldiv2fbdiv[DEFAULT_FBDIV] << RSTPLL_UPPER_FBDIV_SHIFT);
176
177                 // write GLCP_SYS_RSTPPL (GLCP reg 0x14) with clock values  
178                 msrGlcpSysRstpll.lo &= ~(1 << RSTPPL_LOWER_SDRMODE_SHIFT);
179                 wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll);
180
181                 msrGlcpSysRstpll.hi = MDIV_VDIV_FBDIV;
182                 wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll);
183
184                 // Set Reset, LockWait, and SW flag
185                 //      DoReset:
186
187                 // CheckSemiSync proc
188                 // Check for Semi-Sync in GeodeLink and CPU.
189                 // We need to do this here since the strap settings don't account for these bits.
190                 SyncBits = 0;                   // store the sync bits in up ebx
191
192                 // Check for Bypass mode.
193                 if (msrGlcpSysRstpll.lo & RSTPPL_LOWER_BYPASS_SET)
194                 {
195                         // If we are in BYPASS PCI may or may not be sync'd but CPU and GeodeLink will. 
196                         SyncBits |= RSTPPL_LOWER_CPU_SEMI_SYNC_SET;
197                 }
198                 else
199                 {
200                         //      CheckPCIsync:   
201                         // If FBdiv/Mdiv is evenly divisible then set the PCI semi-sync. FB is always greater
202                         // look up the real divider... if we get a 0 we have serious problems
203                         if ( !(fbdiv2plldiv[((msrGlcpSysRstpll.hi >> RSTPLL_UPPER_FBDIV_SHIFT) & 0x3f)] % 
204                                 (((msrGlcpSysRstpll.hi >> RSTPLL_UPPER_MDIV_SHIFT) & 0x0F) + 2)) )
205                         {
206                                 SyncBits |= RSTPPL_LOWER_PCI_SEMI_SYNC_SET;
207                         }
208
209                         //      CheckCPUSync:
210                         // If Vdiv/Mdiv is evenly divisible then set the CPU semi-sync.
211                         // CPU is always greater or equal.
212                         if (!((((msrGlcpSysRstpll.hi >> RSTPLL_UPPER_MDIV_SHIFT) & 0x07) + 2) %
213                                 (((msrGlcpSysRstpll.hi >> RSTPLL_UPPER_VDIV_SHIFT) & 0x0F) + 2)))
214                         {
215                                 SyncBits |= RSTPPL_LOWER_CPU_SEMI_SYNC_SET;
216                         }
217                 }
218
219
220                 //      SetSync:
221                 msrGlcpSysRstpll.lo &= ~(RSTPPL_LOWER_PCI_SEMI_SYNC_SET | RSTPPL_LOWER_CPU_SEMI_SYNC_SET);
222                 msrGlcpSysRstpll.lo |= SyncBits;
223                 wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll);
224                 // CheckSemiSync endp
225
226                 // now we do the reset
227                 // Set hold count to 99 (063h)
228                 msrGlcpSysRstpll.lo &= ~(0x0FF << RSTPPL_LOWER_HOLD_COUNT_SHIFT);
229                 msrGlcpSysRstpll.lo |=  (0x0DE << RSTPPL_LOWER_HOLD_COUNT_SHIFT);
230                 msrGlcpSysRstpll.lo |=  PLLCHECK_COMPLETED;             // Say we are done
231                 wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll);
232
233                 // Don't want to use LOCKWAIT
234                 msrGlcpSysRstpll.lo |= (RSTPPL_LOWER_PLL_RESET_SET + RSTPPL_LOWER_PD_SET);
235                 msrGlcpSysRstpll.lo |= RSTPPL_LOWER_CHIP_RESET_SET;
236                 wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll);
237                 
238                 // You should never get here..... The chip has reset.
239                 post_code(POST_PLL_RESET_FAIL);
240                 while (1);
241
242         } // we haven't configured the PLL; do it now
243         
244 }
245 // End of Goodrich version of pll_reset
246 ///////////////////////////////////////////////////////////////////////////////
247
248 #else // #if USE_GOODRICH_VERSION
249
250 static void pll_reset(void)
251 {
252         msr_t msr;
253         unsigned int sysref, spll_raw, cpu_core, gliu;
254         unsigned mdiv, vdiv, fbdiv;
255
256         /* get CPU core clock in MHZ */
257         cpu_core = calibrate_tsc();
258         print_debug("Cpu core is ");
259         print_debug_hex32(cpu_core);
260         print_debug("\n");
261
262         msr = rdmsr(GLCP_SYS_RSTPLL);
263         if (msr.lo & (1 << GLCP_SYS_RSTPLL_BYPASS)) {
264 #if 0
265                 print_debug("MSR ");
266                 print_debug_hex32(GLCP_SYS_RSTPLL);
267                 print_debug("is ");
268                 print_debug_hex32(msr.hi);
269                 print_debug(":");
270                 print_debug_hex32(msr.lo);
271
272                 msr.hi = PLLMSRhi;
273                 msr.lo = PLLMSRlo;
274                 wrmsr(GLCP_SYS_RSTPLL, msr);
275                 msr.lo |= PLLMSRlo1;
276                 wrmsr(GLCP_SYS_RSTPLL, msr);
277
278                 print_debug("Reset PLL\n");
279
280                 msr.lo |= PLLMSRlo2;
281                 wrmsr(GLCP_SYS_RSTPLL,msr);
282                 print_debug("should not be here\n");
283 #endif
284                 print_err("shit");
285                 while (1)
286                         ;
287         }
288
289         if (msr.lo & GLCP_SYS_RSTPLL_SWFLAGS_MASK) {
290                 /* PLL is already set and we are reboot from PLL reset */
291                 print_debug("reboot from BIOS reset\n");
292                 return;
293         }
294
295         /* get the sysref clock rate */
296         vdiv  = (msr.hi >> GLCP_SYS_RSTPLL_VDIV_SHIFT) & 0x07;
297         vdiv += 2;
298         fbdiv = (msr.hi >> GLCP_SYS_RSTPLL_FBDIV_SHIFT) & 0x3f;
299         fbdiv = fbdiv2plldiv[fbdiv];
300         spll_raw = cpu_core * vdiv;
301         sysref   = spll_raw / fbdiv;
302
303         /* get target memory rate by SPD */
304         //gliu = get_memory_speed();
305
306         msr.hi = 0x00000019;
307         msr.lo = 0x06de0378;
308         wrmsr(0x4c000014, msr);
309         msr.lo |= ((0xde << 16) | (1 << 26) | (1 << 24));
310         wrmsr(0x4c000014, msr);
311
312         print_debug("Reset PLL\n");
313
314         msr.lo |= ((1<<14) |(1<<13) | (1<<0));
315         wrmsr(0x4c000014,msr);
316
317         print_debug("should not be here\n");
318 }
319 #endif // #if USE_GOODRICH_VERSION