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