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