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