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