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