make coherent ht setup capable of non-standard link configurations
[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  * 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 #define WAIT_TIMES 1000
105 static void wait_ap_stop(u8 node) 
106 {
107         unsigned long reg;
108         unsigned long i;
109         for(i=0;i<WAIT_TIMES;i++) {
110                 unsigned long regx;
111                 regx = pci_read_config32(NODE_HT(node),0x6c);
112                 if((regx & (1<<4))==1) break;
113         }
114         reg = pci_read_config32(NODE_HT(node),0x6c);
115         reg &= ~(1<<4);  // clear it
116         pci_write_config32(NODE_HT(node), 0x6c, reg);
117
118 }
119 static void notify_bsp_ap_is_stopped(void)
120 {
121         unsigned long reg;
122         unsigned long apic_id;
123         apic_id = *((volatile unsigned long *)(APIC_DEFAULT_BASE+APIC_ID));
124         apic_id >>= 24;
125 #if 0
126         print_debug("applicaton cpu apic_id: ");
127         print_debug_hex32(apic_id);
128         print_debug("\r\n");
129 #endif
130         /* AP  apic_id == node_id ? */
131         if(apic_id != 0) {
132                 /* set the ColdResetbit to notify BSP that AP is stopped */
133                 reg = pci_read_config32(NODE_HT(apic_id), 0x6C);
134                 reg |= 1<<4;
135                 pci_write_config32(NODE_HT(apic_id), 0x6C, reg);
136         }
137  
138 }
139 //BY LYH END
140
141 static void enable_routing(u8 node)
142 {
143         u32 val;
144
145         /* HT Initialization Control Register
146          * F0:0x6C
147          * [ 0: 0] Routing Table Disable
148          *         0 = Packets are routed according to routing tables
149          *         1 = Packets are routed according to the default link field
150          * [ 1: 1] Request Disable (BSP should clear this)
151          *         0 = Request packets may be generated
152          *         1 = Request packets may not be generated.
153          * [ 3: 2] Default Link (Read-only)
154          *         00 = LDT0
155          *         01 = LDT1
156          *         10 = LDT2
157          *         11 = CPU on same node
158          * [ 4: 4] Cold Reset
159          *         - Scratch bit cleared by a cold reset
160          * [ 5: 5] BIOS Reset Detect
161          *         - Scratch bit cleared by a cold reset
162          * [ 6: 6] INIT Detect
163          *         - Scratch bit cleared by a warm or cold reset not by an INIT
164          *
165          */
166
167         /* Enable routing table */
168         print_debug("Enabling routing table for node ");
169         print_debug_hex32(node);
170
171         val=pci_read_config32(NODE_HT(node), 0x6c);
172         val &= ~((1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0)); 
173         pci_write_config32(NODE_HT(node), 0x6c, val);
174 //BY LYH
175 #if 1
176         if(node!=0) {
177                 wait_ap_stop(node);
178         }
179 #endif
180 //BY LYH END
181
182         print_debug(" done.\r\n");
183 }
184
185 #if CONFIG_MAX_CPUS > 1
186
187 static void rename_temp_node(u8 node)
188 {
189         uint32_t val;
190
191         print_debug("Renaming current temp node to ");
192         print_debug_hex32(node);
193
194         val=pci_read_config32(NODE_HT(7), 0x60);
195         val &= (~7);  /* clear low bits. */
196         val |= node;   /* new node        */
197         pci_write_config32(NODE_HT(7), 0x60, val);
198
199         print_debug(" done.\r\n");
200
201
202 }
203
204 static bool check_connection(u8 src, u8 dest, u8 link)
205 {
206         /* this function does 2 things:
207          * 1) detect whether the coherent HT link is connected.
208          * 2) verify that the coherent hypertransport link
209          *    is established and actually working by reading the
210          *    remote node's vendor/device id
211          */
212
213         u32 val;
214         
215         /* 1) */
216         val=pci_read_config32(NODE_HT(src), 0x98+link);
217         if ( (val&0x17) != 0x03)
218                 return 0;
219
220         /* 2) */
221         val=pci_read_config32(NODE_HT(dest),0);
222         if(val != 0x11001022)
223                 return 0;
224
225         return 1;
226 }
227
228 static void fill_row(u8 node, u8 row, u32 value)
229 {
230 #if 0
231         print_debug("fill_row: pci_write_config32(");
232         print_debug_hex32(NODE_HT(node));
233         print_debug_char(',');
234         print_debug_hex32(0x40 + (row << 2));
235         print_debug_char(',');
236         print_debug_hex32(value);
237         print_debug(")\r\n");
238 #endif  
239         pci_write_config32(NODE_HT(node), 0x40+(row<<2), value);
240 }
241
242 static void setup_row(u8 source, u8 dest, u8 cpus)
243 {
244 #if 0
245         printk_spew("setting up link from node %d to %d (%d cpus)\r\n",
246                 source, dest, cpus);
247 #endif
248
249         fill_row(source,dest,generate_row(source,dest,cpus));
250 }
251
252 static void setup_temp_row(u8 source, u8 dest, u8 cpus)
253 {
254 #if 0
255         printk_spew("setting up temp. link from node %d to %d (%d cpus)\r\n",
256                 source, dest, cpus);
257 #endif
258
259         fill_row(source,7,generate_temp_row(source,dest,cpus));
260 }
261
262 static void setup_node(u8 node, u8 cpus)
263 {
264         u8 row;
265         for(row=0; row<cpus; row++)
266                 setup_row(node, row, cpus);
267 }
268
269 static void setup_remote_row(u8 source, u8 dest, u8 cpus)
270 {
271         fill_row(7, dest, generate_row(source, dest, cpus));
272 }
273
274 static void setup_remote_node(u8 node, u8 cpus)
275 {
276         static const uint8_t pci_reg[] = { 
277                 0x44, 0x4c, 0x54, 0x5c, 0x64, 0x6c, 0x74, 0x7c, 
278                 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78,
279                 0x84, 0x8c, 0x94, 0x9c, 0xa4, 0xac, 0xb4, 0xbc,
280                 0x80, 0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8,
281                 0xc4, 0xcc, 0xd4, 0xdc,
282                 0xc0, 0xc8, 0xd0, 0xd8,
283                 0xe0, 0xe4, 0xe8, 0xec,
284         };
285         uint8_t row;
286         int i;
287 #if 1
288         print_debug("setup_remote_node\r\n");
289 #endif
290         for(row=0; row<cpus; row++)
291                 setup_remote_row(node, row, cpus);
292
293         /* copy the default resource map from node 0 */
294         for(i = 0; i < sizeof(pci_reg)/sizeof(pci_reg[0]); i++) {
295                 uint32_t value;
296                 uint8_t reg;
297                 reg = pci_reg[i];
298 #if 0
299                 print_debug("copying reg: ");
300                 print_debug_hex8(reg);
301                 print_debug("\r\n");
302 #endif
303                 value = pci_read_config32(NODE_MP(0), reg);
304                 pci_write_config32(NODE_MP(7), reg, value);
305
306         }
307 #if 1
308         print_debug("setup_remote_done\r\n");
309 #endif
310 }
311
312 #endif
313
314 #if CONFIG_MAX_CPUS > 2
315 static void setup_temp_node(u8 node, u8 cpus)
316 {
317         u8 row;
318         for(row=0; row<cpus; row++)
319                 fill_row(7,row,generate_row(node,row,cpus));
320 }
321 #endif
322
323 static u8 setup_uniprocessor(void)
324 {
325         print_debug("Enabling UP settings\r\n");
326         disable_probes();
327         return 1;
328 }
329
330 #if CONFIG_MAX_CPUS > 1
331 static u8 setup_smp(void)
332 {
333         u8 cpus=2;
334
335         print_debug("Enabling SMP settings\r\n");
336
337         setup_row(0,0,cpus);
338         /* Setup and check a temporary connection to node 1 */
339         setup_temp_row(0,1,cpus);
340         
341         if (!check_connection(0, 7, CONNECTION_0_1)) {
342                 print_debug("No connection to Node 1.\r\n");
343                 clear_temp_row(0);      /* delete temp connection */
344                 setup_uniprocessor();   /* and get up working     */
345                 return 1;
346         }
347
348         /* We found 2 nodes so far */
349         setup_node(0, cpus);    /* Node 1 is there. Setup Node 0 correctly */
350         setup_remote_node(1, cpus);  /* Setup the routes on the remote node */
351         rename_temp_node(1);    /* Rename Node 7 to Node 1  */
352         enable_routing(1);      /* Enable routing on Node 1 */
353         
354         clear_temp_row(0);      /* delete temporary connection */
355         
356 #if CONFIG_MAX_CPUS > 2
357         cpus=4;
358         
359         /* Setup and check temporary connection from Node 0 to Node 2 */
360         setup_temp_row(0,2,cpus);
361
362         if (!check_connection(0, 7, CONNECTION_0_2)) {
363                 print_debug("No connection to Node 2.\r\n");
364                 clear_temp_row(0);       /* delete temp connection */
365                 return 2;
366         }
367
368         /* We found 3 nodes so far. Now setup a temporary
369          * connection from node 0 to node 3 via node 1
370          */
371
372         setup_temp_row(0,1,cpus); /* temp. link between nodes 0 and 1 */
373         setup_temp_row(1,3,cpus); /* temp. link between nodes 1 and 3 */
374
375         if (!check_connection(1, 7, CONNECTION_1_3)) {
376                 print_debug("No connection to Node 3.\r\n");
377                 clear_temp_row(0);       /* delete temp connection */
378                 clear_temp_row(1);       /* delete temp connection */
379                 return 2;
380         }
381
382         /* We found 4 nodes so far. Now setup all nodes for 4p */
383
384         setup_node(0, cpus);  /* The first 2 nodes are configured    */
385         setup_node(1, cpus);  /* already. Just configure them for 4p */
386         
387         setup_temp_row(0,2,cpus);
388         setup_temp_node(2,cpus);
389         rename_temp_node(2);
390         enable_routing(2);
391   
392         setup_temp_row(0,1,cpus);
393         setup_temp_row(1,3,cpus);
394         setup_temp_node(3,cpus);
395         rename_temp_node(3);
396         enable_routing(3);      /* enable routing on node 3 (temp.) */
397         
398         clear_temp_row(0);
399         clear_temp_row(1);
400         clear_temp_row(2);
401         clear_temp_row(3);
402
403 #endif
404         print_debug_hex32(cpus);
405         print_debug(" nodes initialized.\r\n");
406         return cpus;
407 }
408 #endif
409
410 #if CONFIG_MAX_CPUS > 1
411 static unsigned detect_mp_capabilities(unsigned cpus)
412 {
413         unsigned node, row, mask;
414         bool mp_cap=TRUE;
415
416 #if 1
417         print_debug("detect_mp_capabilities: ");
418         print_debug_hex32(cpus);
419         print_debug("\r\n");
420 #endif
421         if (cpus>2)
422                 mask=0x06;      /* BigMPCap */
423         else
424                 mask=0x02;      /* MPCap    */
425
426         for (node=0; node<cpus; node++) {
427                 if ((pci_read_config32(NODE_MC(node), 0xe8) & mask)!=mask)
428                         mp_cap=FALSE;
429         }
430
431         if (mp_cap)
432                 return cpus;
433
434         /* one of our cpus is not mp capable */
435
436         print_debug("One of the CPUs is not MP capable. Going back to UP\r\n");
437
438         for (node=cpus; node>0; node--)
439             for (row=cpus; row>0; row--)
440                 fill_row(NODE_HT(node-1), row-1, DEFAULT);
441         
442         return setup_uniprocessor();
443 }
444
445 #endif
446
447 /* this is a shrunken cpuid. */
448
449 static unsigned int cpuid(unsigned int op)
450 {
451         unsigned int ret;
452
453         asm volatile ( "cpuid" : "=a" (ret) : "a" (op));
454
455         return ret;
456 }
457
458 static void coherent_ht_finalize(unsigned cpus)
459 {
460         int node;
461         bool rev_a0;
462         
463         /* set up cpu count and node count and enable Limit
464          * Config Space Range for all available CPUs.
465          * Also clear non coherent hypertransport bus range
466          * registers on Hammer A0 revision.
467          */
468
469 #if 1
470         print_debug("coherent_ht_finalize\r\n");
471 #endif
472         rev_a0=((cpuid(1)&0xffff)==0x0f10);
473
474         for (node=0; node<cpus; node++) {
475                 u32 val;
476                 val=pci_read_config32(NODE_HT(node), 0x60);
477                 val &= (~0x000F0070);
478                 val |= ((cpus-1)<<16)|((cpus-1)<<4);
479                 pci_write_config32(NODE_HT(node),0x60,val);
480
481                 val=pci_read_config32(NODE_HT(node), 0x68);
482                 val |= 0x0f00c800;  // 0x00008000->0f00c800 BY LYH
483                 pci_write_config32(NODE_HT(node),0x68,val);
484
485                 if (rev_a0) {
486                         pci_write_config32(NODE_HT(node),0x94,0);
487                         pci_write_config32(NODE_HT(node),0xb4,0);
488                         pci_write_config32(NODE_HT(node),0xd4,0);
489                 }
490         }
491 #if 1
492         print_debug("done\r\n");
493 #endif
494 }
495
496 static int setup_coherent_ht_domain(void)
497 {
498         unsigned cpus;
499         int reset_needed = 0;
500
501         enable_bsp_routing();
502
503 #if CONFIG_MAX_CPUS == 1
504         cpus=setup_uniprocessor();
505 #else
506         cpus=setup_smp();
507         cpus=detect_mp_capabilities(cpus);
508 #endif
509         coherent_ht_finalize(cpus);
510
511         /* this should probably go away again. */
512         coherent_ht_mainboard(cpus);
513         return reset_needed;
514 }