8342778bab2a1a17245c857e9dddffc5f94b6579
[coreboot.git] / src / northbridge / intel / i440lx / northbridge.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2007 Uwe Hermann <uwe@hermann-uwe.de>
5  * Copyright (C) 2009 Maciej Pijanka <maciej.pijanka@gmail.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
20  */
21 #include <console/console.h>
22 #include <arch/io.h>
23 #include <stdint.h>
24 #include <device/device.h>
25 #include <device/pci.h>
26 #include <device/pci_ids.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <bitops.h>
30 #include <cpu/cpu.h>
31 #include <pc80/keyboard.h>
32 #include "chip.h"
33 #include "northbridge.h"
34 #include "i440lx.h"
35
36 /* This code is mostly same as 440BX created by Uwe Hermann,
37  * i done only very minor changes like renamed functions to 440lx etc
38  * Maciej
39  */
40
41 /* TODO:
42  * - maybe this could print Northbridge i440LX Init?
43  */
44 static void northbridge_init(device_t dev)
45 {
46         printk(BIOS_SPEW, "Northbridge Init\n");
47 }
48
49 static struct device_operations northbridge_operations = {
50         .read_resources   = pci_dev_read_resources,
51         .set_resources    = pci_dev_set_resources,
52         .enable_resources = pci_dev_enable_resources,
53         .init             = northbridge_init,
54         .enable           = 0,
55         .ops_pci          = 0,
56 };
57
58 static const struct pci_driver northbridge_driver __pci_driver = {
59         .ops = &northbridge_operations,
60         .vendor = PCI_VENDOR_ID_INTEL,
61         .device = 0x7180,
62 };
63
64 static void ram_resource(device_t dev, unsigned long index,
65         unsigned long basek, unsigned long sizek)
66 {
67         struct resource *resource;
68
69         if (!sizek) {
70                 return;
71         }
72         resource = new_resource(dev, index);
73         resource->base  = ((resource_t)basek) << 10;
74         resource->size  = ((resource_t)sizek) << 10;
75         resource->flags =  IORESOURCE_MEM | IORESOURCE_CACHEABLE | \
76                 IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
77 }
78
79 static void tolm_test(void *gp, struct device *dev, struct resource *new)
80 {
81         struct resource **best_p = gp;
82         struct resource *best;
83         best = *best_p;
84         if (!best || (best->base > new->base)) {
85                 best = new;
86         }
87         *best_p = best;
88 }
89
90 static uint32_t find_pci_tolm(struct bus *bus)
91 {
92         struct resource *min;
93         uint32_t tolm;
94         min = 0;
95         search_bus_resources(bus, IORESOURCE_MEM, IORESOURCE_MEM, tolm_test, &min);
96         tolm = 0xffffffffUL;
97         if (min && tolm > min->base) {
98                 tolm = min->base;
99         }
100         return tolm;
101 }
102
103 #if CONFIG_WRITE_HIGH_TABLES==1
104 #define HIGH_TABLES_SIZE 64     // maximum size of high tables in KB
105 extern uint64_t high_tables_base, high_tables_size;
106 #endif
107
108 static void i440lx_domain_set_resources(device_t dev)
109 {
110         device_t mc_dev;
111         uint32_t pci_tolm;
112
113         pci_tolm = find_pci_tolm(dev->link_list);
114         mc_dev = dev->link_list->children;
115         if (mc_dev) {
116                 unsigned long tomk, tolmk;
117                 int idx;
118
119                 /* Figure out which areas are/should be occupied by RAM. The
120                  * value of the highest DRB denotes the end of the physical
121                  * memory (in units of 8MB).
122                  */
123                 tomk = ((unsigned long)pci_read_config8(mc_dev, DRB7));
124
125                 /* Convert to KB. */
126                 tomk *= (8 * 1024);
127
128                 printk(BIOS_DEBUG, "Setting RAM size to %lu MB\n", tomk / 1024);
129
130                 /* Compute the top of low memory. */
131                 tolmk = pci_tolm / 1024;
132
133                 if (tolmk >= tomk) {
134                         /* The PCI hole does not overlap the memory. */
135                         tolmk = tomk;
136                 }
137
138                 /* Report the memory regions. */
139                 idx = 10;
140                 ram_resource(dev, idx++, 0, 640);
141                 ram_resource(dev, idx++, 768, tolmk - 768);
142
143 #if CONFIG_WRITE_HIGH_TABLES==1
144                 /* Leave some space for ACPI, PIRQ and MP tables */
145                 high_tables_base = (tomk - HIGH_TABLES_SIZE) * 1024;
146                 high_tables_size = HIGH_TABLES_SIZE * 1024;
147 #endif
148         }
149         assign_resources(dev->link_list);
150 }
151
152 static struct device_operations pci_domain_ops = {
153         .read_resources         = pci_domain_read_resources,
154         .set_resources          = i440lx_domain_set_resources,
155         .enable_resources       = NULL,
156         .init                   = NULL,
157         .scan_bus               = pci_domain_scan_bus,
158 };
159
160 static void cpu_bus_init(device_t dev)
161 {
162         initialize_cpus(dev->link_list);
163 }
164
165 static void cpu_bus_noop(device_t dev)
166 {
167 }
168
169 static struct device_operations cpu_bus_ops = {
170         .read_resources   = cpu_bus_noop,
171         .set_resources    = cpu_bus_noop,
172         .enable_resources = cpu_bus_noop,
173         .init             = cpu_bus_init,
174         .scan_bus         = 0,
175 };
176
177 static void enable_dev(struct device *dev)
178 {
179         /* Set the operations if it is a special bus type */
180         if (dev->path.type == DEVICE_PATH_PCI_DOMAIN) {
181                 dev->ops = &pci_domain_ops;
182                 pci_set_method(dev);
183         }
184         else if (dev->path.type == DEVICE_PATH_APIC_CLUSTER) {
185                 dev->ops = &cpu_bus_ops;
186         }
187 }
188
189 struct chip_operations northbridge_intel_i440lx_ops = {
190         CHIP_NAME("Intel 82443LX (440LX) Northbridge")
191         .enable_dev = enable_dev,
192 };