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