YhLu's changes to resolve several memory and other problems.
[coreboot.git] / src / northbridge / amd / amdk8 / coherent_ht.c
1 /* coherent hypertransport initialization for AMD64 
2  * written by Stefan Reinauer <stepan@openbios.info>
3  * (c) 2003 by SuSE Linux AG
4  *
5  * This code is licensed under GPL.
6  */
7
8 /*
9  * This algorithm assumes a grid configuration as follows:
10  *
11  * nodes :  1    2    4    6    8
12  * org.  :  1x1  2x1  2x2  2x3  2x4
13  *
14  */
15
16 #include <device/pci_def.h>
17 #include "arch/romcc_io.h"
18
19 /*
20  * 
21  */
22
23 /* when generating a temporary row configuration we
24  * don't want broadcast to be enabled for that node.
25  */
26
27 #define generate_temp_row(x...) ((generate_row(x)&(~0x0f0000))|0x010000)
28 #define clear_temp_row(x)       fill_row(x,7,DEFAULT)
29 #define enable_bsp_routing()    enable_routing(0)
30
31 #define NODE_HT(x) PCI_DEV(0,24+x,0)
32 #define NODE_MP(x) PCI_DEV(0,24+x,1)
33 #define NODE_MC(x) PCI_DEV(0,24+x,3)
34
35 #define DEFAULT 0x00010101      /* default row entry */
36
37 typedef uint8_t u8;
38 typedef uint32_t u32;
39 typedef int8_t bool;
40
41 #define TRUE  (-1)
42 #define FALSE (0)
43
44 static void disable_probes(void)
45 {
46         /* disable read/write/fill probes for uniprocessor setup
47          * they don't make sense if only one cpu is available
48          */
49
50         /* Hypetransport Transaction Control Register 
51          * F0:0x68
52          * [ 0: 0] Disable read byte probe
53          *         0 = Probes issues
54          *         1 = Probes not issued
55          * [ 1: 1] Disable Read Doubleword probe
56          *         0 = Probes issued
57          *         1 = Probes not issued
58          * [ 2: 2] Disable write byte probes
59          *         0 = Probes issued
60          *         1 = Probes not issued
61          * [ 3: 3] Disable Write Doubleword Probes
62          *         0 = Probes issued
63          *         1 = Probes not issued.
64          * [10:10] Disable Fill Probe
65          *         0 = Probes issued for cache fills
66          *         1 = Probes not issued for cache fills.
67          */
68
69         u32 val;
70
71         print_debug("Disabling read/write/fill probes for UP... ");
72
73         val=pci_read_config32(NODE_HT(0), 0x68);
74         val |= (1<<10)|(1<<9)|(1<<8)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|(1 << 0);
75         pci_write_config32(NODE_HT(0), 0x68, val);
76
77         print_debug("done.\r\n");
78
79 }
80 //BY LYH
81 #define WAIT_TIMES 1000
82 static void wait_ap_stop(u8 node) 
83 {
84         unsigned long reg;
85         unsigned long i;
86         for(i=0;i<WAIT_TIMES;i++) {
87                 unsigned long regx;
88                 regx = pci_read_config32(NODE_HT(node),0x6c);
89                 if((regx & (1<<4))==1) break;
90         }
91         reg = pci_read_config32(NODE_HT(node),0x6c);
92         reg &= ~(1<<4);  // clear it
93         pci_write_config32(NODE_HT(node), 0x6c, reg);
94
95 }
96 static void notify_bsp_ap_is_stopped(void)
97 {
98         unsigned long reg;
99         unsigned long apic_id;
100         apic_id = *((volatile unsigned long *)(APIC_DEFAULT_BASE+APIC_ID));
101         apic_id >>= 24;
102 /*      print_debug("applicaton cpu apic_id: ");
103         print_debug_hex32(apic_id);
104         print_debug("\r\n");
105         }*/
106         if(apic_id!=0) { //AP  apic_id == node_id ??
107 //              set the ColdResetbit to notify BSP that AP is stopped
108                 reg = pci_read_config32(NODE_HT(apic_id), 0x6C);
109                 reg |= 1<<4;
110                 pci_write_config32(NODE_HT(apic_id),  0x6C, reg);
111         }
112  
113 }
114 //BY LYH END
115
116 static void enable_routing(u8 node)
117 {
118         u32 val;
119
120         /* HT Initialization Control Register
121          * F0:0x6C
122          * [ 0: 0] Routing Table Disable
123          *         0 = Packets are routed according to routing tables
124          *         1 = Packets are routed according to the default link field
125          * [ 1: 1] Request Disable (BSP should clear this)
126          *         0 = Request packets may be generated
127          *         1 = Request packets may not be generated.
128          * [ 3: 2] Default Link (Read-only)
129          *         00 = LDT0
130          *         01 = LDT1
131          *         10 = LDT2
132          *         11 = CPU on same node
133          * [ 4: 4] Cold Reset
134          *         - Scratch bit cleared by a cold reset
135          * [ 5: 5] BIOS Reset Detect
136          *         - Scratch bit cleared by a cold reset
137          * [ 6: 6] INIT Detect
138          *         - Scratch bit cleared by a warm or cold reset not by an INIT
139          *
140          */
141
142         /* Enable routing table */
143         print_debug("Enabling routing table for node ");
144         print_debug_hex32(node);
145
146         val=pci_read_config32(NODE_HT(node), 0x6c);
147         val &= ~((1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0)); 
148         pci_write_config32(NODE_HT(node), 0x6c, val);
149 //BY LYH
150 #if 1
151         if(node!=0) {
152                 wait_ap_stop(node);
153         }
154 #endif
155 //BY LYH END
156
157         print_debug(" done.\r\n");
158 }
159
160 #if MAX_CPUS > 1
161
162 static void rename_temp_node(u8 node)
163 {
164         uint32_t val;
165
166         print_debug("Renaming current temp node to ");
167         print_debug_hex32(node);
168
169         val=pci_read_config32(NODE_HT(7), 0x60);
170         val &= (~7);  /* clear low bits. */
171         val |= node;   /* new node        */
172         pci_write_config32(NODE_HT(7), 0x60, val);
173
174         print_debug(" done.\r\n");
175
176
177 }
178
179 static bool check_connection(u8 src, u8 dest, u8 link)
180 {
181         /* this function does 2 things:
182          * 1) detect whether the coherent HT link is connected.
183          * 2) verify that the coherent hypertransport link
184          *    is established and actually working by reading the
185          *    remote node's vendor/device id
186          */
187
188 #define UP      0x00
189 #define ACROSS  0x20
190 #define DOWN    0x40
191
192         u32 val;
193         
194         /* 1) */
195         val=pci_read_config32(NODE_HT(src), 0x98+link);
196         if ( (val&0x17) != 0x03)
197                 return 0;
198
199         /* 2) */
200         val=pci_read_config32(NODE_HT(dest),0);
201         if(val != 0x11001022)
202                 return 0;
203
204         return 1;
205 }
206
207 static void fill_row(u8 node, u8 row, u32 value)
208 {
209 #if 0
210         print_debug("fill_row: pci_write_config32(");
211         print_debug_hex32(NODE_HT(node));
212         print_debug_char(',');
213         print_debug_hex32(0x40 + (row << 2));
214         print_debug_char(',');
215         print_debug_hex32(value);
216         print_debug(")\r\n");
217 #endif  
218         pci_write_config32(NODE_HT(node), 0x40+(row<<2), value);
219 }
220
221 static void setup_row(u8 source, u8 dest, u8 cpus)
222 {
223 #if 0
224         printk_spew("setting up link from node %d to %d (%d cpus)\r\n",
225                 source, dest, cpus);
226 #endif
227
228         fill_row(source,dest,generate_row(source,dest,cpus));
229 }
230
231 static void setup_temp_row(u8 source, u8 dest, u8 cpus)
232 {
233 #if 0
234         printk_spew("setting up temp. link from node %d to %d (%d cpus)\r\n",
235                 source, dest, cpus);
236 #endif
237
238         fill_row(source,7,generate_temp_row(source,dest,cpus));
239 }
240
241 static void setup_node(u8 node, u8 cpus)
242 {
243         u8 row;
244         for(row=0; row<cpus; row++)
245                 setup_row(node, row, cpus);
246 }
247
248 static void setup_remote_row(u8 source, u8 dest, u8 cpus)
249 {
250         fill_row(7, dest, generate_row(source, dest, cpus));
251 }
252
253 static void setup_remote_node(u8 node, u8 cpus)
254 {
255         static const uint8_t pci_reg[] = { 
256                 0x44, 0x4c, 0x54, 0x5c, 0x64, 0x6c, 0x74, 0x7c, 
257                 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78,
258                 0x84, 0x8c, 0x94, 0x9c, 0xa4, 0xac, 0xb4, 0xbc,
259                 0x80, 0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8,
260                 0xc4, 0xcc, 0xd4, 0xdc,
261                 0xc0, 0xc8, 0xd0, 0xd8,
262                 0xe0, 0xe4, 0xe8, 0xec,
263         };
264         uint8_t row;
265         int i;
266 #if 1
267         print_debug("setup_remote_node\r\n");
268 #endif
269         for(row=0; row<cpus; row++)
270                 setup_remote_row(node, row, cpus);
271
272         /* copy the default resource map from node 0 */
273         for(i = 0; i < sizeof(pci_reg)/sizeof(pci_reg[0]); i++) {
274                 uint32_t value;
275                 uint8_t reg;
276                 reg = pci_reg[i];
277 #if 0
278                 print_debug("copying reg: ");
279                 print_debug_hex8(reg);
280                 print_debug("\r\n");
281 #endif
282                 value = pci_read_config32(NODE_MP(0), reg);
283                 pci_write_config32(NODE_MP(7), reg, value);
284
285         }
286 #if 1
287         print_debug("setup_remote_done\r\n");
288 #endif
289 }
290
291 #endif
292
293 #if MAX_CPUS > 2
294 static void setup_temp_node(u8 node, u8 cpus)
295 {
296         u8 row;
297         for(row=0; row<cpus; row++)
298                 fill_row(7,row,generate_row(node,row,cpus));
299 }
300 #endif
301
302 static u8 setup_uniprocessor(void)
303 {
304         print_debug("Enabling UP settings\r\n");
305         disable_probes();
306         return 1;
307 }
308
309 #if MAX_CPUS > 1
310 static u8 setup_smp(void)
311 {
312         u8 cpus=2;
313
314         print_debug("Enabling SMP settings\r\n");
315
316         setup_row(0,0,cpus);
317         /* Setup and check a temporary connection to node 1 */
318         setup_temp_row(0,1,cpus);
319         
320         if (!check_connection(0, 7, ACROSS)) {  // Link: ACROSS
321                 print_debug("No connection to Node 1.\r\n");
322                 clear_temp_row(0);      /* delete temp connection */
323                 setup_uniprocessor();   /* and get up working     */
324                 return 1;
325         }
326
327         /* We found 2 nodes so far */
328         setup_node(0, cpus);    /* Node 1 is there. Setup Node 0 correctly */
329         setup_remote_node(1, cpus);  /* Setup the routes on the remote node */
330         rename_temp_node(1);    /* Rename Node 7 to Node 1  */
331         enable_routing(1);      /* Enable routing on Node 1 */
332         
333         clear_temp_row(0);      /* delete temporary connection */
334         
335 #if MAX_CPUS > 2
336         cpus=4;
337         
338         /* Setup and check temporary connection from Node 0 to Node 2 */
339         setup_temp_row(0,2,cpus);
340
341         if (!check_connection(0, 7, UP)) {      // Link: UP
342                 print_debug("No connection to Node 2.\r\n");
343                 clear_temp_row(0);       /* delete temp connection */
344                 return 2;
345         }
346
347         /* We found 3 nodes so far. Now setup a temporary
348          * connection from node 0 to node 3 via node 1
349          */
350
351         setup_temp_row(0,1,cpus); /* temp. link between nodes 0 and 1 */
352         setup_temp_row(1,3,cpus); /* temp. link between nodes 1 and 3 */
353
354         if (!check_connection(1, 7, UP)) {      // Link: UP
355                 print_debug("No connection to Node 3.\r\n");
356                 clear_temp_row(0);       /* delete temp connection */
357                 clear_temp_row(1);       /* delete temp connection */
358                 return 2;
359         }
360
361         /* We found 4 nodes so far. Now setup all nodes for 4p */
362
363         setup_node(0, cpus);  /* The first 2 nodes are configured    */
364         setup_node(1, cpus);  /* already. Just configure them for 4p */
365         
366         setup_temp_row(0,2,cpus);
367         setup_temp_node(2,cpus);
368         rename_temp_node(2);
369         enable_routing(2);
370   
371         setup_temp_row(0,1,cpus);
372         setup_temp_row(1,3,cpus);
373         setup_temp_node(3,cpus);
374         rename_temp_node(3);
375         enable_routing(3);      /* enable routing on node 3 (temp.) */
376         
377         clear_temp_row(0);
378         clear_temp_row(1);
379         clear_temp_row(2);
380         clear_temp_row(3);
381
382 #endif
383         print_debug_hex32(cpus);
384         print_debug(" nodes initialized.\r\n");
385         return cpus;
386 }
387 #endif
388
389 #if MAX_CPUS > 1
390 static unsigned detect_mp_capabilities(unsigned cpus)
391 {
392         unsigned node, row, mask;
393         bool mp_cap=TRUE;
394
395 #if 1
396         print_debug("detect_mp_capabilities: ");
397         print_debug_hex32(cpus);
398         print_debug("\r\n");
399 #endif
400         if (cpus>2)
401                 mask=0x06;      /* BigMPCap */
402         else
403                 mask=0x02;      /* MPCap    */
404
405         for (node=0; node<cpus; node++) {
406                 if ((pci_read_config32(NODE_MC(node), 0xe8) & mask)!=mask)
407                         mp_cap=FALSE;
408         }
409
410         if (mp_cap)
411                 return cpus;
412
413         /* one of our cpus is not mp capable */
414
415         print_debug("One of the CPUs is not MP capable. Going back to UP\r\n");
416
417         for (node=cpus; node>0; node--)
418             for (row=cpus; row>0; row--)
419                 fill_row(NODE_HT(node-1), row-1, DEFAULT);
420         
421         return setup_uniprocessor();
422 }
423
424 #endif
425
426 /* this is a shrunken cpuid. */
427
428 static unsigned int cpuid(unsigned int op)
429 {
430         unsigned int ret;
431
432         asm volatile ( "cpuid" : "=a" (ret) : "a" (op));
433
434         return ret;
435 }
436
437 static void coherent_ht_finalize(unsigned cpus)
438 {
439 //BY LYH 
440 #if 1
441      static const unsigned int register_values[] = {
442         PCI_ADDR(0, 0x18, 0, 0x84), 0x88ff9c05, 0x11000020,
443         PCI_ADDR(0, 0x18, 0, 0xa4), 0x88ff9c05, 0x11000020,
444         PCI_ADDR(0, 0x18, 0, 0xc4), 0x88ff9c05, 0x770000d0,
445         PCI_ADDR(0, 0x19, 0, 0x84), 0x88ff9c05, 0x770000d0,
446         PCI_ADDR(0, 0x19, 0, 0xa4), 0x88ff9c05, 0x11000020,
447         PCI_ADDR(0, 0x19, 0, 0xc4), 0x88ff9c05, 0x770000d0,
448
449
450         PCI_ADDR(0, 0x18, 0, 0x88), 0xfffff0ff, 0x00000400,
451         PCI_ADDR(0, 0x18, 0, 0xa8), 0xfffff0ff, 0x00000500,
452         PCI_ADDR(0, 0x18, 0, 0xc8), 0xfffff0ff, 0x00000000,
453         PCI_ADDR(0, 0x19, 0, 0x88), 0xfffff0ff, 0x00000000,
454         PCI_ADDR(0, 0x19, 0, 0xa8), 0xfffff0ff, 0x00000500,
455         PCI_ADDR(0, 0x19, 0, 0xc8), 0xfffff0ff, 0x00000000,
456
457         PCI_ADDR(0, 0x18, 0, 0x94), 0xff0000ff, 0x00ff0000,
458         PCI_ADDR(0, 0x18, 0, 0xb4), 0xff0000ff, 0x00000000,
459         PCI_ADDR(0, 0x18, 0, 0xd4), 0xff0000ff, 0x00000000,
460         PCI_ADDR(0, 0x19, 0, 0x94), 0xff0000ff, 0x00000000,
461         PCI_ADDR(0, 0x19, 0, 0xb4), 0xff0000ff, 0x00000000,
462         PCI_ADDR(0, 0x19, 0, 0xd4), 0xff0000ff, 0x00000000,
463
464       };
465         int i;
466         int max;
467
468
469         device_t dev;
470         unsigned where;
471         unsigned long reg;
472 #endif
473 //BY LYH END
474
475         int node;
476         bool rev_a0;
477         
478         /* set up cpu count and node count and enable Limit
479          * Config Space Range for all available CPUs.
480          * Also clear non coherent hypertransport bus range
481          * registers on Hammer A0 revision.
482          */
483
484 #if 1
485         print_debug("coherent_ht_finalize\r\n");
486 #endif
487         rev_a0=((cpuid(1)&0xffff)==0x0f10);
488
489         for (node=0; node<cpus; node++) {
490                 u32 val;
491                 val=pci_read_config32(NODE_HT(node), 0x60);
492                 val &= (~0x000F0070);
493                 val |= ((cpus-1)<<16)|((cpus-1)<<4);
494                 pci_write_config32(NODE_HT(node),0x60,val);
495
496                 val=pci_read_config32(NODE_HT(node), 0x68);
497                 val |= 0x0f00c800;  // 0x00008000->0f00c800 BY LYH
498                 pci_write_config32(NODE_HT(node),0x68,val);
499
500                 if (rev_a0) {
501                         pci_write_config32(NODE_HT(node),0x94,0);
502                         pci_write_config32(NODE_HT(node),0xb4,0);
503                         pci_write_config32(NODE_HT(node),0xd4,0);
504                 }
505         }
506 //BY LYH
507 #if 1
508         print_debug("setting up coherent ht domain....\r\n");
509         max = sizeof(register_values)/sizeof(register_values[0]);
510         for(i = 0; i < max; i += 3) {
511 #if 0
512                 print_debug_hex32(i);
513                 print_debug(": ");
514                 print_debug_hex32(register_values[i]);
515                 print_debug(" <-");
516                 print_debug_hex32(register_values[i+2]);
517                 print_debug("\r\n");
518 #endif
519                 dev = register_values[i] & ~0xff;
520                 where = register_values[i] & 0xff;
521                 reg = pci_read_config32(dev, where);
522                 reg &= register_values[i+1];
523                 reg |= register_values[i+2];
524                 pci_write_config32(dev, where, reg);
525         }
526 #endif
527 //BY LYH END
528
529 #if 1
530         print_debug("done\r\n");
531 #endif
532 }
533
534 static int setup_coherent_ht_domain(void)
535 {
536         unsigned cpus;
537         int reset_needed = 0;
538
539         enable_bsp_routing();
540
541 #if MAX_CPUS == 1
542         cpus=setup_uniprocessor();
543 #else
544         cpus=setup_smp();
545         cpus=detect_mp_capabilities(cpus);
546 #endif
547         coherent_ht_finalize(cpus);
548
549         return reset_needed;
550 }