5e6b68ace683ad4fa10855ea2d418d83f04536e2
[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 #define POST_CODE(x) outb(x, 0x80)
119
120 // PLLCHECK_COMPLETED is the "we've already done this" flag
121 #define PLLCHECK_COMPLETED (1 << RSTPLL_LOWER_SWFLAGS_SHIFT)
122
123 #ifndef RSTPPL_LOWER_BYPASS_SET
124 #define RSTPPL_LOWER_BYPASS_SET (1 << GLCP_SYS_RSTPLL_BYPASS)
125 #endif // RSTPPL_LOWER_BYPASS_SET
126
127 #define DEFAULT_MDIV    3
128 #define DEFAULT_VDIV    2
129 #define DEFAULT_FBDIV   22      // 366/244 ; 24 400/266 018 ;300/200 
130
131 static void pll_reset(void)
132 {
133         msr_t msrGlcpSysRstpll;
134         unsigned MDIV_VDIV_FBDIV;
135         unsigned SyncBits;                      // store the sync bits in up ebx
136
137         // clear the Bypass bit
138         
139         // If the straps say we are in bypass and the syspll is not AND there are no software
140         // bits set then FS2 or something set up the PLL and we should not change it.
141         
142         msrGlcpSysRstpll = rdmsr(GLCP_SYS_RSTPLL);
143         msrGlcpSysRstpll.lo &= ~RSTPPL_LOWER_BYPASS_SET;
144         wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll);
145
146         // If the "we've already been here" flag is set, don't reconfigure the pll
147         if ( !(msrGlcpSysRstpll.lo & PLLCHECK_COMPLETED ) )
148         { // we haven't configured the PLL; do it now
149         
150                 // Store PCI33(0)/66(1), SDR(0)/DDR(1), and CRT(0)/TFT(1) in upper esi to get to the
151                 // correct Strap Table.
152                 POST_CODE(POST_PLL_INIT);
153                 
154                 // configure for DDR
155                 msrGlcpSysRstpll.lo &= ~(1 << RSTPPL_LOWER_SDRMODE_SHIFT);
156                 wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll);
157                 
158                 // Use Manual settings
159                 //      UseManual:
160                 POST_CODE(POST_PLL_MANUAL);
161
162                 // DIV settings manually entered.
163                 // ax = VDIV, upper eax = MDIV, upper ecx = FbDIV
164                 // use gs and fs since we don't need them.
165                 
166                 //      ProgramClocks:
167                 // ax = VDIV, upper eax = MDIV, upper ecx = FbDIV
168                 // move everything into ebx
169                 // VDIV
170                 MDIV_VDIV_FBDIV = ((DEFAULT_VDIV - 2) << RSTPLL_UPPER_VDIV_SHIFT);
171
172                 // MDIV
173                 MDIV_VDIV_FBDIV |= ((DEFAULT_MDIV - 2) << RSTPLL_UPPER_MDIV_SHIFT);
174
175                 // FbDIV
176                 MDIV_VDIV_FBDIV |= (plldiv2fbdiv[DEFAULT_FBDIV] << RSTPLL_UPPER_FBDIV_SHIFT);
177
178                 // write GLCP_SYS_RSTPPL (GLCP reg 0x14) with clock values  
179                 msrGlcpSysRstpll.lo &= ~(1 << RSTPPL_LOWER_SDRMODE_SHIFT);
180                 wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll);
181
182                 msrGlcpSysRstpll.hi = MDIV_VDIV_FBDIV;
183                 wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll);
184
185                 // Set Reset, LockWait, and SW flag
186                 //      DoReset:
187
188                 // CheckSemiSync proc
189                 // Check for Semi-Sync in GeodeLink and CPU.
190                 // We need to do this here since the strap settings don't account for these bits.
191                 SyncBits = 0;                   // store the sync bits in up ebx
192
193                 // Check for Bypass mode.
194                 if (msrGlcpSysRstpll.lo & RSTPPL_LOWER_BYPASS_SET)
195                 {
196                         // If we are in BYPASS PCI may or may not be sync'd but CPU and GeodeLink will. 
197                         SyncBits |= RSTPPL_LOWER_CPU_SEMI_SYNC_SET;
198                 }
199                 else
200                 {
201                         //      CheckPCIsync:   
202                         // If FBdiv/Mdiv is evenly divisible then set the PCI semi-sync. FB is always greater
203                         // look up the real divider... if we get a 0 we have serious problems
204                         if ( !(fbdiv2plldiv[((msrGlcpSysRstpll.hi >> RSTPLL_UPPER_FBDIV_SHIFT) & 0x3f)] % 
205                                 (((msrGlcpSysRstpll.hi >> RSTPLL_UPPER_MDIV_SHIFT) & 0x0F) + 2)) )
206                         {
207                                 SyncBits |= RSTPPL_LOWER_PCI_SEMI_SYNC_SET;
208                         }
209
210                         //      CheckCPUSync:
211                         // If Vdiv/Mdiv is evenly divisible then set the CPU semi-sync.
212                         // CPU is always greater or equal.
213                         if (!((((msrGlcpSysRstpll.hi >> RSTPLL_UPPER_MDIV_SHIFT) & 0x07) + 2) %
214                                 (((msrGlcpSysRstpll.hi >> RSTPLL_UPPER_VDIV_SHIFT) & 0x0F) + 2)))
215                         {
216                                 SyncBits |= RSTPPL_LOWER_CPU_SEMI_SYNC_SET;
217                         }
218                 }
219
220
221                 //      SetSync:
222                 msrGlcpSysRstpll.lo &= ~(RSTPPL_LOWER_PCI_SEMI_SYNC_SET | RSTPPL_LOWER_CPU_SEMI_SYNC_SET);
223                 msrGlcpSysRstpll.lo |= SyncBits;
224                 wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll);
225                 // CheckSemiSync endp
226
227                 // now we do the reset
228                 // Set hold count to 99 (063h)
229                 msrGlcpSysRstpll.lo &= ~(0x0FF << RSTPPL_LOWER_HOLD_COUNT_SHIFT);
230                 msrGlcpSysRstpll.lo |=  (0x0DE << RSTPPL_LOWER_HOLD_COUNT_SHIFT);
231                 msrGlcpSysRstpll.lo |=  PLLCHECK_COMPLETED;             // Say we are done
232                 wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll);
233
234                 // Don't want to use LOCKWAIT
235                 msrGlcpSysRstpll.lo |= (RSTPPL_LOWER_PLL_RESET_SET + RSTPPL_LOWER_PD_SET);
236                 msrGlcpSysRstpll.lo |= RSTPPL_LOWER_CHIP_RESET_SET;
237                 wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll);
238                 
239                 // You should never get here..... The chip has reset.
240                 POST_CODE(POST_PLL_RESET_FAIL);
241                 while (1);
242
243         } // we haven't configured the PLL; do it now
244         
245 }
246 // End of Goodrich version of pll_reset
247 ///////////////////////////////////////////////////////////////////////////////
248
249 #else // #if USE_GOODRICH_VERSION
250
251 static void pll_reset(void)
252 {
253         msr_t msr;
254         unsigned int sysref, spll_raw, cpu_core, gliu;
255         unsigned mdiv, vdiv, fbdiv;
256
257         /* get CPU core clock in MHZ */
258         cpu_core = calibrate_tsc();
259         print_debug("Cpu core is ");
260         print_debug_hex32(cpu_core);
261         print_debug("\n");
262
263         msr = rdmsr(GLCP_SYS_RSTPLL);
264         if (msr.lo & (1 << GLCP_SYS_RSTPLL_BYPASS)) {
265 #if 0
266                 print_debug("MSR ");
267                 print_debug_hex32(GLCP_SYS_RSTPLL);
268                 print_debug("is ");
269                 print_debug_hex32(msr.hi);
270                 print_debug(":");
271                 print_debug_hex32(msr.lo);
272
273                 msr.hi = PLLMSRhi;
274                 msr.lo = PLLMSRlo;
275                 wrmsr(GLCP_SYS_RSTPLL, msr);
276                 msr.lo |= PLLMSRlo1;
277                 wrmsr(GLCP_SYS_RSTPLL, msr);
278
279                 print_debug("Reset PLL\n\r");
280
281                 msr.lo |= PLLMSRlo2;
282                 wrmsr(GLCP_SYS_RSTPLL,msr);
283                 print_debug("should not be here\n\r");
284 #endif
285                 print_err("shit");
286                 while (1)
287                         ;
288         }
289
290         if (msr.lo & GLCP_SYS_RSTPLL_SWFLAGS_MASK) {
291                 /* PLL is already set and we are reboot from PLL reset */
292                 print_debug("reboot from BIOS reset\n\r");
293                 return;
294         }
295
296         /* get the sysref clock rate */
297         vdiv  = (msr.hi >> GLCP_SYS_RSTPLL_VDIV_SHIFT) & 0x07;
298         vdiv += 2;
299         fbdiv = (msr.hi >> GLCP_SYS_RSTPLL_FBDIV_SHIFT) & 0x3f;
300         fbdiv = fbdiv2plldiv[fbdiv];
301         spll_raw = cpu_core * vdiv;
302         sysref   = spll_raw / fbdiv;
303
304         /* get target memory rate by SPD */
305         //gliu = get_memory_speed();
306
307         msr.hi = 0x00000019;
308         msr.lo = 0x06de0378;
309         wrmsr(0x4c000014, msr);
310         msr.lo |= ((0xde << 16) | (1 << 26) | (1 << 24));
311         wrmsr(0x4c000014, msr);
312
313         print_debug("Reset PLL\n\r");
314
315         msr.lo |= ((1<<14) |(1<<13) | (1<<0));
316         wrmsr(0x4c000014,msr);
317
318         print_debug("should not be here\n\r");
319 }
320 #endif // #if USE_GOODRICH_VERSION