added AGP support for AMD K8
[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 0
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                 } 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))) /* 640 */ && 
67                     (mem[idx-1].sizek > ((8*64)+(16*16))) /* 768 */ ) {
68 #warning "FIXME: this left 0xA0000 to 0xBFFFF undefined"
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                         } else {
89                                 mem[idx - 1].basek = 4*1024*1024;
90                                 mem[idx - 1].sizek -= (4*1024*1024 - mmio_basek);
91                         }
92                 }
93         }
94 #if 1
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 static unsigned int amdk8_scan_chains(device_t dev, unsigned int max)
165 {
166         unsigned nodeid;
167         unsigned link;
168
169         nodeid = amdk8_nodeid(dev);
170
171         printk_spew("amdk8_scan_chains max: %d starting...\n", max);
172
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
191                  * 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
210                  * register skip this bus */
211                 if (config_reg > 0xec) {
212                         continue;
213                 }
214
215                 /* Set up the primary, secondary and subordinate bus numbers.
216                  * We have no idea how many busses are behind this bridge yet,
217                  * so we set the subordinate bus number to 0xff for the moment.
218                  */
219                 dev->link[link].secondary = ++max;
220                 dev->link[link].subordinate = 0xff;
221
222                 /* Read the existing primary/secondary/subordinate bus
223                  * number configuration.
224                  */
225                 busses = pci_read_config32(dev, dev->link[link].cap + 0x14);
226                 config_busses = f1_read_config32(config_reg);
227                 
228                 /* Configure the bus numbers for this bridge: the configuration
229                  * transactions will not be propagates by the bridge if it is
230                  * not correctly configured
231                  */
232                 busses &= 0xff000000;
233                 busses |= (((unsigned int)(dev->bus->secondary) << 0) |
234                         ((unsigned int)(dev->link[link].secondary) << 8) |
235                         ((unsigned int)(dev->link[link].subordinate) << 16));
236                 pci_write_config32(dev, dev->link[link].cap + 0x14, busses);
237
238                 config_busses &= 0x000fc88;
239                 config_busses |= 
240                         (3 << 0) |  /* rw enable, no device compare */
241                         (( nodeid & 7) << 4) | 
242                         (( link & 3 ) << 8) |  
243                         ((dev->link[link].secondary) << 16) |
244                         ((dev->link[link].subordinate) << 24);
245                 f1_write_config32(config_reg, config_busses);
246
247                 printk_spew("Hyper transport scan link: %d max: %d\n",
248                              link, max);
249
250                 /* Now we can scan all of the subordinate busses i.e. the
251                  * chain on the hypertranport link */
252                 max = hypertransport_scan_chain(&dev->link[link], max);
253
254                 printk_spew("Hyper transport scan link: %d new max: %d\n",
255                              link, max);
256
257                 /* We know the number of busses behind this bridge.  Set the
258                  * subordinate bus number to it's real value
259                  */
260                 dev->link[link].subordinate = max;
261                 busses = (busses & 0xff00ffff) |
262                         ((unsigned int) (dev->link[link].subordinate) << 16);
263                 pci_write_config32(dev, dev->link[link].cap + 0x14, busses);
264
265                 config_busses = (config_busses & 0x00ffffff) |
266                         (dev->link[link].subordinate << 24);
267                 f1_write_config32(config_reg, config_busses);
268                 printk_spew("Hypertransport scan link done\n");
269         }
270
271         printk_spew("amdk8_scan_chains max: %d done\n", max);
272         return max;
273 }
274
275 static unsigned amdk8_find_iopair(unsigned nodeid, unsigned link)
276 {
277         unsigned free_reg, reg;
278
279         free_reg = 0;
280         for (reg = 0xc0; reg <= 0xd8; reg += 0x8) {
281                 uint32_t base, limit;
282                 base  = f1_read_config32(reg);
283                 limit = f1_read_config32(reg + 0x4);
284                 /* Do I have a free register */
285                 if (!free_reg && ((base & 3) == 0)) {
286                         free_reg = reg;
287                 }
288                 /* Do I have a match for this node and link? */
289                 if (((base & 3) == 3) &&
290                     ((limit & 7) == nodeid) &&
291                     (((limit >> 4) & 3) == link)) {
292                         break;
293                 }
294         }
295         /* If I didn't find an exact match return a free register */
296         if (reg > 0xd8) {
297                 reg = free_reg;
298         }
299         /* Return an available I/O pair or 0 on failure */
300         return reg;
301 }
302
303 static unsigned amdk8_find_mempair(unsigned nodeid, unsigned link)
304 {
305         unsigned free_reg, reg;
306
307         free_reg = 0;
308         for (reg = 0x80; reg <= 0xb8; reg += 0x8) {
309                 uint32_t base, limit;
310                 base  = f1_read_config32(reg);
311                 limit = f1_read_config32(reg + 0x4);
312                 /* Do I have a free register */
313                 if (!free_reg && ((base & 3) == 0)) {
314                         free_reg = reg;
315                 }
316                 /* Do I have a match for this node and link? */
317                 if (((base & 3) == 3) &&
318                     ((limit & 7) == nodeid) &&
319                     (((limit >> 4) & 3) == link)) {
320                         break;
321                 }
322         }
323         /* If I didn't find an exact match return a free register */
324         if (reg > 0xb8) {
325                 reg = free_reg;
326         }
327         /* Return an available I/O pair or 0 on failure */
328         return reg;
329 }
330
331 static void amdk8_link_read_bases(device_t dev, unsigned nodeid, unsigned link)
332 {
333         unsigned int reg = dev->resources;
334         unsigned index;
335         
336         /* Initialize the io space constraints on the current bus */
337         index = amdk8_find_iopair(nodeid, link);
338         if (index) {
339                 dev->resource[reg].base  = 0;
340                 dev->resource[reg].size  = 0;
341                 dev->resource[reg].align = log2(HT_IO_HOST_ALIGN);
342                 dev->resource[reg].gran  = log2(HT_IO_HOST_ALIGN);
343                 dev->resource[reg].limit = 0xffffUL;
344                 dev->resource[reg].flags = IORESOURCE_IO;
345                 dev->resource[reg].index = index | (link & 0x3);
346                 compute_allocate_resource(&dev->link[link], &dev->resource[reg], 
347                                           IORESOURCE_IO, IORESOURCE_IO);
348                 reg++;
349         }
350
351         /* Initialize the memory constraints on the current bus */
352         index = amdk8_find_mempair(nodeid, link);
353         if (index) {
354                 dev->resource[reg].base  = 0;
355                 dev->resource[reg].size  = 0;
356                 dev->resource[reg].align = log2(HT_MEM_HOST_ALIGN);
357                 dev->resource[reg].gran  = log2(HT_MEM_HOST_ALIGN);
358                 dev->resource[reg].limit = 0xffffffffUL;
359                 dev->resource[reg].flags = IORESOURCE_MEM;
360                 dev->resource[reg].index = index | (link & 0x3);
361                 compute_allocate_resource(&dev->link[link], &dev->resource[reg], 
362                                           IORESOURCE_MEM, IORESOURCE_MEM);
363                 reg++;
364         }
365         dev->resources = reg;
366 }
367
368 static void amdk8_read_resources(device_t dev)
369 {
370         unsigned nodeid, link;
371         nodeid = amdk8_nodeid(dev);
372         dev->resources = 0;
373         memset(&dev->resource, 0, sizeof(dev->resource));
374         for (link = 0; link < dev->links; link++) {
375                 if (dev->link[link].children) {
376                         amdk8_link_read_bases(dev, nodeid, link);
377                 }
378         }
379 }
380
381 static void amdk8_set_resource(device_t dev, struct resource *resource,
382                                unsigned nodeid)
383 {
384         unsigned long rbase, rlimit;
385         unsigned reg, link;
386
387         /* Make certain the resource has actually been set */
388         if (!(resource->flags & IORESOURCE_ASSIGNED)) {
389                 return;
390         }
391
392         /* If I have already stored this resource don't worry about it */
393         if (resource->flags & IORESOURCE_STORED) {
394                 return;
395         }
396         
397         /* Only handle PCI memory and IO resources */
398         if (!(resource->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
399                 return;
400
401         /* Get the base address */
402         rbase = resource->base;
403         
404         /* Get the limit (rounded up) */
405         rlimit = rbase + ((resource->size + resource->align - 1UL) &
406                           ~(resource->align -1)) - 1UL;
407
408         /* Get the register and link */
409         reg  = resource->index & ~3;
410         link = resource->index & 3;
411
412         if (resource->flags & IORESOURCE_IO) {
413                 uint32_t base, limit;
414                 compute_allocate_resource(&dev->link[link], resource,
415                                           IORESOURCE_IO, IORESOURCE_IO);
416                 base  = f1_read_config32(reg);
417                 limit = f1_read_config32(reg + 0x4);
418                 base  &= 0xfe000fcc;
419                 base  |= rbase  & 0x01fff000;
420                 base  |= 3;
421                 limit &= 0xfe000fc8;
422                 limit |= rlimit & 0x01fff000;
423                 limit |= (link & 3) << 4;
424                 limit |= (nodeid & 7);
425
426                 if (dev->link[link].bridge_ctrl & PCI_BRIDGE_CTL_VGA) {
427                         base |= PCI_IO_BASE_VGA_EN;
428                 }
429                 if (dev->link[link].bridge_ctrl & PCI_BRIDGE_CTL_NO_ISA) {
430                         base |= PCI_IO_BASE_NO_ISA;
431                 }
432                 f1_write_config32(reg + 0x4, limit);
433                 f1_write_config32(reg, base);
434         } else if (resource->flags & IORESOURCE_MEM) {
435                 uint32_t base, limit;
436                 compute_allocate_resource(&dev->link[link], resource,
437                                           IORESOURCE_MEM, IORESOURCE_MEM);
438                 base  = f1_read_config32(reg);
439                 limit = f1_read_config32(reg + 0x4);
440                 base  &= 0x000000f0;
441                 base  |= (rbase & 0xffff0000) >> 8;
442                 base  |= 3;
443                 limit &= 0x00000048;
444                 limit |= (rlimit & 0xffff0000) >> 8;
445                 limit |= (link & 3) << 4;
446                 limit |= (nodeid & 7);
447                 f1_write_config32(reg + 0x4, limit);
448                 f1_write_config32(reg, base);
449         }
450         resource->flags |= IORESOURCE_STORED;
451         printk_debug("%s %02x <- [0x%08lx - 0x%08lx] node %d link %d %s\n",
452                      dev_path(dev), reg, rbase, rlimit, nodeid, link,
453                      (resource->flags & IORESOURCE_IO)? "io": "mem");
454 }
455
456 static void amdk8_set_resources(device_t dev)
457 {
458         unsigned nodeid, link;
459         int i;
460
461         /* Find the nodeid */
462         nodeid = amdk8_nodeid(dev);     
463
464         /* Set each resource we have found */
465         for (i = 0; i < dev->resources; i++) {
466                 amdk8_set_resource(dev, &dev->resource[i], nodeid);
467         }
468
469         for (link = 0; link < dev->links; link++) {
470                 struct bus *bus;
471                 bus = &dev->link[link];
472                 if (bus->children) {
473                         assign_resources(bus);
474                 }
475         }
476 }
477
478 /**
479  * @brief Scan root bus for AMD K8 systems
480  *
481  * @param root the root device structure
482  * @max the current bus number scanned so far, usually 0x00
483  *
484  * The root device in a AMD K8 system is not at Bus 0, Device 0, Fun 0
485  * as other PCI based systems. The northbridge is at Bus 0, Device 0x18,
486  * Fun 0. We have to call the pci_scan_bus() with PCI_DEVFN(0x18,0) as
487  * the starting device instead of PCI_DEVFN(0x00, 0) as in the default
488  * root_dev_scan_pci_bus().
489  *
490  * This function is set up as the default scan_bus() method for mainboards'
491  * device_operations for AMD K8 mainboards in mainboard.c
492  *
493  * @see device_operation()
494  * @see root_dev_scan_pci_bus()
495  */
496 unsigned int amdk8_scan_root_bus(device_t root, unsigned int max)
497 {
498         unsigned reg;
499
500         printk_spew("amdk8_scan_root_bus\n");
501
502         /* Unmap all of the HT chains by clearing the Configuration
503          * Map registers */
504         for (reg = 0xe0; reg <= 0xec; reg += 4) {
505                 f1_write_config32(reg, 0);
506         }
507
508         max = pci_scan_bus(&root->link[0], PCI_DEVFN(0x18, 0), 0xff, max);
509
510         printk_spew("amdk8_scan_root_bus: done\n");
511         return max;
512 }
513
514 static void mcf0_control_init(struct device *dev)
515 {
516         uint32_t cmd;
517
518 #if 1   
519         printk_spew("NB: Function 0 Misc Control.. ");
520         /* improve latency and bandwith on HT */
521         cmd = pci_read_config32(dev, 0x68);
522         cmd &= 0xffff80ff;
523         cmd |= 0x00004800;
524         pci_write_config32(dev, 0x68, cmd );
525 #endif
526
527 #if 0   
528         /* over drive the ht port to 1000 Mhz */
529         cmd = pci_read_config32(dev, 0xa8);
530         cmd &= 0xfffff0ff;
531         cmd |= 0x00000600;
532         pci_write_config32(dev, 0xdc, cmd );
533 #endif
534
535         printk_spew("done.\n");
536 }
537
538
539 static void amdk8_enable_resources(struct device *dev)
540 {
541         uint16_t ctrl;
542         unsigned link;
543         unsigned int vgalink = -1;
544
545         ctrl = pci_read_config16(dev, PCI_BRIDGE_CONTROL);
546         ctrl |= dev->link[0].bridge_ctrl;
547         printk_debug("%s bridge ctrl <- %04x\n", dev_path(dev), ctrl);
548         pci_write_config16(dev, PCI_BRIDGE_CONTROL, ctrl);
549
550 #if 1
551         /* No, don;t do it here, we should create phantom PCI resource
552          * for leagcy VGA resources in VGA device driver and use the
553          * generic resource allocation/assignment code to do it
554          *
555          * TOO BAD, the generic resource allcation code refuses to do
556          * abything with VGA and the AMDK8 resource code does want
557          * more than one discontinous IO/MEM regions */
558
559         /* let's see what link VGA is on */
560         for (link = 0; link < dev->links; link++) {
561                 device_t child;
562                 printk_err("Kid %d of k8: bridge ctrl says: 0x%x\n",
563                            link, dev->link[link].bridge_ctrl);
564                 if (dev->link[link].bridge_ctrl & PCI_BRIDGE_CTL_VGA)
565                         vgalink = link;
566         }
567
568         if (vgalink != -1) {
569                 uint32_t base, limit;
570                 unsigned reg;
571                 /* now allocate an MMPAIR and point it to the CPU0,
572                  * LINK=vgalink */
573                 /* Set up mem pair
574                  * FIXME: add amdk8_find_free_mempair() */
575                 //reg = amdk8_find_mempair(0, vgalink);
576                 reg = 0x90;
577                 /* Set base of 0xa0000 */
578                 base = 0xa03;
579                 limit = 0xd00 | (vgalink << 4);
580                 printk_debug("setting MMIO routing for VGA reg:0x%x, base: 0x%x, limit 0x%x\n",
581                              reg, base, limit);
582                 f1_write_config32(reg, base);
583                 f1_write_config32(reg + 4, limit);
584         }
585 #endif
586
587         pci_dev_enable_resources(dev);
588 }
589
590 static struct device_operations northbridge_operations = {
591         .read_resources   = amdk8_read_resources,
592         .set_resources    = amdk8_set_resources,
593         .enable_resources = amdk8_enable_resources,
594         .init             = mcf0_control_init,
595         .scan_bus         = amdk8_scan_chains,
596         .enable           = 0,
597 };
598
599 static struct pci_driver mcf0_driver __pci_driver = {
600         .ops    = &northbridge_operations,
601         .vendor = PCI_VENDOR_ID_AMD,
602         .device = 0x1100,
603 };
604
605 static void enumerate(struct chip *chip)
606 {
607         chip_enumerate(chip);
608         chip->dev->ops = &northbridge_operations;
609 }
610
611 struct chip_control northbridge_amd_amdk8_control = {
612         .name   = "AMD K8 Northbridge",
613         .enumerate = enumerate,
614 };