missing file.
[coreboot.git] / src / northbridge / amd / amdk8 / northbridge.c
1 #include <console/console.h>
2 #include <arch/io.h>
3 #include <stdint.h>
4 #include <mem.h>
5 #include <part/sizeram.h>
6 #include <device/device.h>
7 #include <device/pci.h>
8 #include <device/hypertransport.h>
9 #include <device/chip.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <bitops.h>
13 #include "chip.h"
14 #include "northbridge.h"
15 #include "amdk8.h"
16
17 struct mem_range *sizeram(void)
18 {
19         unsigned long mmio_basek;
20         static struct mem_range mem[10];
21         device_t dev;
22         int i, idx;
23
24 #warning "FIXME handle interleaved nodes"
25         dev = dev_find_slot(0, PCI_DEVFN(0x18, 1));
26         if (!dev) {
27                 printk_err("Cannot find PCI: 0:18.1\n");
28                 return 0;
29         }
30         mmio_basek = (dev_root.resource[1].base >> 10);
31         /* Round mmio_basek to something the processor can support */
32         mmio_basek &= ~((1 << 6) -1);
33
34 #if 1
35 #warning "FIXME improve mtrr.c so we don't use up all of the mtrrs with a 64M MMIO hole"
36         /* Round the mmio hold to 256M */
37         mmio_basek &= ~((256*1024) - 1);
38 #endif
39
40 #if 1
41         printk_debug("mmio_base: %dKB\n", mmio_basek);
42 #endif
43
44         for(idx = i = 0; i < 8; i++) {
45                 uint32_t base, limit;
46                 unsigned basek, limitk, sizek;
47                 base  = pci_read_config32(dev, 0x40 + (i<<3));
48                 limit = pci_read_config32(dev, 0x44 + (i<<3));
49                 if ((base & ((1<<1)|(1<<0))) != ((1<<1)|(1<<0))) {
50                         continue;
51                 }
52                 basek = (base & 0xffff0000) >> 2;
53                 limitk = ((limit + 0x00010000) & 0xffff0000) >> 2;
54                 sizek = limitk - basek;
55                 if ((idx > 0) &&
56                         ((mem[idx -1].basek + mem[idx - 1].sizek) == basek)) {
57                         mem[idx -1].sizek += sizek;
58                 }
59                 else {
60                         mem[idx].basek = basek;
61                         mem[idx].sizek = sizek;
62                         idx++;
63                 }
64         
65                 /* see if we need a hole from 0xa0000 to 0xbffff */
66                 if((mem[idx-1].basek < ((8*64)+(8*16))) && 
67                    (mem[idx-1].sizek > ((8*64)+(16*16)))) {
68                         mem[idx].basek = (8*64)+(16*16);
69                         mem[idx].sizek = mem[idx-1].sizek - ((8*64)+(16*16));
70                         mem[idx-1].sizek = ((8*64)+(8*16)) - mem[idx-1].basek;
71                         idx++;
72                 }       
73                 
74                 /* See if I need to split the region to accomodate pci memory space */
75                 if ((mem[idx - 1].basek <= mmio_basek) &&
76                         ((mem[idx - 1].basek + mem[idx - 1].sizek) >  mmio_basek)) {
77                         if (mem[idx - 1].basek < mmio_basek) {
78                                 unsigned pre_sizek;
79                                 pre_sizek = mmio_basek - mem[idx - 1].basek;
80                                 mem[idx].basek = mmio_basek;
81                                 mem[idx].sizek = mem[idx - 1].sizek - pre_sizek;
82                                 mem[idx - 1].sizek = pre_sizek;
83                                 idx++;
84                         }
85                         if ((mem[idx - 1].basek + mem[idx - 1].sizek) <= 4*1024*1024) {
86                                 idx -= 1;
87                         }
88                         else {
89                                 mem[idx - 1].basek = 4*1024*1024;
90                                 mem[idx - 1].sizek -= (4*1024*1024 - mmio_basek);
91                         }
92                 }
93         }
94 #if 0
95         for(i = 0; i < idx; i++) {
96                 printk_debug("mem[%d].basek = %08x mem[%d].sizek = %08x\n",
97                         i, mem[i].basek, i, mem[i].sizek);
98         }
99 #endif
100         while(idx < sizeof(mem)/sizeof(mem[0])) {
101                 mem[idx].basek = 0;
102                 mem[idx].sizek = 0;
103                 idx++;
104         }
105         return mem;
106 }
107
108 #define F1_DEVS 8
109 static device_t __f1_dev[F1_DEVS];
110
111 #if 0
112 static void debug_f1_devs(void)
113 {
114         int i;
115         for(i = 0; i < F1_DEVS; i++) {
116                 device_t dev;
117                 dev = __f1_dev[i];
118                 if (dev) {
119                         printk_debug("__f1_dev[%d]: %s bus: %p\n",
120                                 i, dev_path(dev), dev->bus);
121                 }
122         }
123 }
124 #endif
125
126 static void get_f1_devs(void)
127 {
128         int i;
129         if (__f1_dev[0]) {
130                 return;
131         }
132         for(i = 0; i < F1_DEVS; i++) {
133                 __f1_dev[i] = dev_find_slot(0, PCI_DEVFN(0x18 + i, 1));
134         }
135         if (!__f1_dev[0]) {
136                 die("Cannot find 0:0x18.1\n");
137         }
138 }
139
140 static uint32_t f1_read_config32(unsigned reg)
141 {
142         get_f1_devs();
143         return pci_read_config32(__f1_dev[0], reg);
144 }
145
146 static void f1_write_config32(unsigned reg, uint32_t value)
147 {
148         int i;
149         get_f1_devs();
150         for(i = 0; i < F1_DEVS; i++) {
151                 device_t dev;
152                 dev = __f1_dev[i];
153                 if (dev) {
154                         pci_write_config32(dev, reg, value);
155                 }
156         }
157 }
158
159 static unsigned int amdk8_nodeid(device_t dev)
160 {
161         return (dev->path.u.pci.devfn >> 3) - 0x18;
162 }
163
164
165 static unsigned int amdk8_scan_chains(device_t dev, unsigned int max)
166 {
167         unsigned nodeid;
168         unsigned link;
169         nodeid = amdk8_nodeid(dev);
170 #if 1
171         printk_debug("amdk8_scan_chains max: %d starting...\n", max);
172 #endif
173         for(link = 0; link < dev->links; link++) {
174                 uint32_t link_type;
175                 uint32_t busses, config_busses;
176                 unsigned free_reg, config_reg;
177                 dev->link[link].cap = 0x80 + (link *0x20);
178                 do {
179                         link_type = pci_read_config32(dev, dev->link[link].cap + 0x18);
180                 } while(link_type & ConnectionPending);
181                 if (!(link_type & LinkConnected)) {
182                         continue;
183                 }
184                 do {
185                         link_type = pci_read_config32(dev, dev->link[link].cap + 0x18);
186                 } while(!(link_type & InitComplete));
187                 if (!(link_type & NonCoherent)) {
188                         continue;
189                 }
190                 /* See if there is an available configuration space mapping register in function 1. */
191                 free_reg = 0;
192                 for(config_reg = 0xe0; config_reg <= 0xec; config_reg += 4) {
193                         uint32_t config;
194                         config = f1_read_config32(config_reg);
195                         if (!free_reg && ((config & 3) == 0)) {
196                                 free_reg = config_reg;
197                                 continue;
198                         }
199                         if (((config & 3) == 3) && 
200                                 (((config >> 4) & 7) == nodeid) &&
201                                 (((config >> 8) & 3) == link)) {
202                                 break;
203                         }
204                 }
205                 if (free_reg && (config_reg > 0xec)) {
206                         config_reg = free_reg;
207                 }
208                 /* If we can't find an available configuration space mapping register skip this bus */
209                 if (config_reg > 0xec) {
210                         continue;
211                 }
212
213                 /* Set up the primary, secondary and subordinate bus numbers.  We have
214                  * no idea how many busses are behind this bridge yet, so we set the subordinate
215                  * bus number to 0xff for the moment.
216                  */
217                 dev->link[link].secondary = ++max;
218                 dev->link[link].subordinate = 0xff;
219
220                 /* Read the existing primary/secondary/subordinate bus
221                  * number configuration.
222                  */
223                 busses = pci_read_config32(dev, dev->link[link].cap + 0x14);
224                 config_busses = f1_read_config32(config_reg);
225                 
226                 /* Configure the bus numbers for this bridge: the configuration
227                  * transactions will not be propagates by the bridge if it is not
228                  * correctly configured
229                  */
230                 busses &= 0xff000000;
231                 busses |= (((unsigned int)(dev->bus->secondary) << 0) |
232                         ((unsigned int)(dev->link[link].secondary) << 8) |
233                         ((unsigned int)(dev->link[link].subordinate) << 16));
234                 pci_write_config32(dev, dev->link[link].cap + 0x14, busses);
235
236                 config_busses &= 0x0000ffff;
237                 config_busses |= ((dev->link[link].secondary) << 16) |
238                         ((dev->link[link].subordinate) << 24);
239                 f1_write_config32(config_reg, config_busses);
240
241 #if 1
242                 printk_debug("Hyper transport scan link: %d max: %d\n", link, max);
243 #endif          
244                 /* Now we can scan all of the subordinate busses i.e. the chain on the hypertranport link */
245                 max = hypertransport_scan_chain(&dev->link[link], max);
246
247 #if 1
248                 printk_debug("Hyper transport scan link: %d new max: %d\n", link, max);
249 #endif          
250
251                 /* We know the number of busses behind this bridge.  Set the subordinate
252                  * bus number to it's real value
253                  */
254                 dev->link[link].subordinate = max;
255                 busses = (busses & 0xff00ffff) |
256                         ((unsigned int) (dev->link[link].subordinate) << 16);
257                 pci_write_config32(dev, dev->link[link].cap + 0x14, busses);
258
259                 config_busses &= 0x000fc88;
260                 config_busses |= 
261                         (3 << 0) |  /* rw enable, no device compare */
262                         (( nodeid & 7) << 4) | 
263                         (( link & 3 ) << 8) |  
264                         ((dev->link[link].secondary) << 16) |
265                         ((dev->link[link].subordinate) << 24);
266                 f1_write_config32(config_reg, config_busses);
267 #if 1
268                 printk_debug("Hypertransport scan link done\n");
269 #endif          
270         }
271 #if 1
272         printk_debug("amdk8_scan_chains max: %d done\n", max);
273 #endif
274         return max;
275 }
276
277
278 static unsigned amdk8_find_iopair(unsigned nodeid, unsigned link)
279 {
280         unsigned free_reg, reg;
281
282         free_reg = 0;
283         for(reg = 0xc0; reg <= 0xd8; reg += 0x8) {
284                 uint32_t base, limit;
285                 base  = f1_read_config32(reg);
286                 limit = f1_read_config32(reg + 0x4);
287                 /* Do I have a free register */
288                 if (!free_reg && ((base & 3) == 0)) {
289                         free_reg = reg;
290                 }
291                 /* Do I have a match for this node and link? */
292                 if (((base & 3) == 3) &&
293                         ((limit & 3) == nodeid) &&
294                         (((limit >> 4) & 3) == link)) {
295                         break;
296                 }
297         }
298         /* If I didn't find an exact match return a free register */
299         if (reg > 0xd8) {
300                 reg = free_reg;
301         }
302         /* Return an available I/O pair or 0 on failure */
303         return reg;
304 }
305
306 static unsigned amdk8_find_mempair(unsigned nodeid, unsigned link)
307 {
308         unsigned free_reg, reg;
309         free_reg = 0;
310         for(reg = 0x80; reg <= 0xb8; reg += 0x8) {
311                 uint32_t base, limit;
312                 base  = f1_read_config32(reg);
313                 limit = f1_read_config32(reg + 0x4);
314                 /* Do I have a free register */
315                 if (!free_reg && ((base & 3) == 0)) {
316                         free_reg = reg;
317                 }
318                 /* Do I have a match for this node and link? */
319                 if (((base & 3) == 3) &&
320                         ((limit & 3) == nodeid) &&
321                         (((limit >> 4) & 3) == link)) {
322                         break;
323                 }
324         }
325         /* If I didn't find an exact match return a free register */
326         if (reg > 0xb8) {
327                 reg = free_reg;
328         }
329         /* Return an available I/O pair or 0 on failure */
330         return reg;
331 }
332
333 static void amdk8_link_read_bases(device_t dev, unsigned nodeid, unsigned link)
334 {
335         unsigned int reg = dev->resources;
336         unsigned index;
337         
338         /* Initialize the io space constraints on the current bus */
339         index = amdk8_find_iopair(nodeid, link);
340         if (index) {
341                 dev->resource[reg].base  = 0;
342                 dev->resource[reg].size  = 0;
343                 dev->resource[reg].align = log2(HT_IO_HOST_ALIGN);
344                 dev->resource[reg].gran  = log2(HT_IO_HOST_ALIGN);
345                 dev->resource[reg].limit = 0xffffUL;
346                 dev->resource[reg].flags = IORESOURCE_IO;
347                 dev->resource[reg].index = index | (link & 0x3);
348                 compute_allocate_resource(&dev->link[link], &dev->resource[reg], 
349                         IORESOURCE_IO, IORESOURCE_IO);
350                 reg++;
351         }
352
353         /* Initialize the memory constraints on the current bus */
354         index = amdk8_find_mempair(nodeid, link);
355         if (index) {
356                 dev->resource[reg].base  = 0;
357                 dev->resource[reg].size  = 0;
358                 dev->resource[reg].align = log2(HT_MEM_HOST_ALIGN);
359                 dev->resource[reg].gran  = log2(HT_MEM_HOST_ALIGN);
360                 dev->resource[reg].limit = 0xffffffffUL;
361                 dev->resource[reg].flags = IORESOURCE_MEM;
362                 dev->resource[reg].index = index | (link & 0x3);
363                 compute_allocate_resource(&dev->link[link], &dev->resource[reg], 
364                         IORESOURCE_MEM, IORESOURCE_MEM);
365                 reg++;
366         }
367         dev->resources = reg;
368 }
369
370 static void amdk8_read_resources(device_t dev)
371 {
372         unsigned nodeid, link;
373         nodeid = amdk8_nodeid(dev);
374         dev->resources = 0;
375         memset(&dev->resource, 0, sizeof(dev->resource));
376         for(link = 0; link < dev->links; link++) {
377                 if (dev->link[link].children) {
378                         amdk8_link_read_bases(dev, nodeid, link);
379                 }
380         }
381 }
382
383 static void amdk8_set_resource(device_t dev, struct resource *resource, unsigned nodeid)
384 {
385         unsigned long rbase, rlimit;
386         unsigned reg, link;
387         /* Make certain the resource has actually been set */
388         if (!(resource->flags & IORESOURCE_SET)) {
389                 return;
390         }
391         
392         /* Only handle PCI memory and IO resources */
393         if (!(resource->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
394                 return;
395
396         /* Get the base address */
397         rbase = resource->base;
398         
399         /* Get the limit (rounded up) */
400         rlimit = rbase + ((resource->size + resource->align - 1UL) & ~(resource->align -1)) - 1UL;
401
402         /* Get the register and link */
403         reg  = resource->index & ~3;
404         link = resource->index & 3;
405         
406         if (resource->flags & IORESOURCE_IO) {
407                 uint32_t base, limit;
408                 compute_allocate_resource(&dev->link[link], resource,
409                         IORESOURCE_IO, IORESOURCE_IO);
410                 base  = f1_read_config32(reg);
411                 limit = f1_read_config32(reg + 0x4);
412                 base  &= 0xfe000fcc;
413                 base  |= rbase  & 0x01fff000;
414                 base  |= 3;
415                 limit &= 0xfe000fc8;
416                 limit |= rlimit & 0x01fff000;
417                 limit |= (link & 3) << 4;
418                 limit |= (nodeid & 3);
419                 f1_write_config32(reg + 0x4, limit);
420                 f1_write_config32(reg, base);
421         }
422         else if (resource->flags & IORESOURCE_MEM) {
423                 uint32_t base, limit;
424                 compute_allocate_resource(&dev->link[link], resource,
425                         IORESOURCE_MEM, IORESOURCE_MEM);
426                 base  = f1_read_config32(reg);
427                 limit = f1_read_config32(reg + 0x4);
428                 base  &= 0x000000f0;
429                 base  |= (rbase & 0xffff0000) >> 8;
430                 base  |= 3;
431                 limit &= 0x00000048;
432                 limit |= (rlimit & 0xffff0000) >> 8;
433                 limit |= (link & 3) << 4;
434                 limit |= (nodeid & 3);
435                 f1_write_config32(reg + 0x4, limit);
436                 f1_write_config32(reg, base);
437         }
438         printk_debug(
439                 "%s %02x <- [0x%08lx - 0x%08lx] node %d link %d %s\n",
440                 dev_path(dev),
441                 reg, 
442                 rbase, rlimit,
443                 nodeid, link,
444                 (resource->flags & IORESOURCE_IO)? "io": "mem");
445 }
446
447 static void amdk8_set_resources(device_t dev)
448 {
449         unsigned nodeid, link;
450         int i;
451
452         /* Find the nodeid */
453         nodeid = amdk8_nodeid(dev);     
454
455         /* Set each resource we have found */
456         for(i = 0; i < dev->resources; i++) {
457                 amdk8_set_resource(dev, &dev->resource[i], nodeid);
458         }
459         
460         for(link = 0; link < dev->links; link++) {
461                 struct bus *bus;
462                 bus = &dev->link[link];
463                 if (bus->children) {
464                         assign_resources(bus);
465                 }
466         }
467 }
468
469 unsigned int amdk8_scan_root_bus(device_t root, unsigned int max)
470 {
471         unsigned reg;
472         /* Unmap all of HT chains */
473         for(reg = 0xe0; reg <= 0xec; reg += 4) {
474                 f1_write_config32(reg, 0);
475         }
476         max = pci_scan_bus(&root->link[0], PCI_DEVFN(0x18, 0), 0xff, max);
477         return max;
478 }
479
480 static struct device_operations northbridge_operations = {
481         .read_resources   = amdk8_read_resources,
482         .set_resources    = amdk8_set_resources,
483         .enable_resources = pci_dev_enable_resources,
484         .init             = 0,
485         .scan_bus         = amdk8_scan_chains,
486         .enable           = 0,
487 };
488
489
490 static void enumerate(struct chip *chip)
491 {
492         chip_enumerate(chip);
493         chip->dev->ops = &northbridge_operations;
494 }
495
496 struct chip_control northbridge_amd_amdk8_control = {
497         .name   = "AMD K8 Northbridge",
498         .enumerate = enumerate,
499 };