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