blob: 5bc1025c4c0a933874204c99209ece78cd354e8e [file] [log] [blame]
Stefan Reinauer278534d2008-10-29 04:51:07 +00001/*
2 * This file is part of the coreboot project.
3 *
Stefan Reinauer43b29cf2009-03-06 19:11:52 +00004 * Copyright (C) 2007-2009 coresystems GmbH
Stefan Reinauer278534d2008-10-29 04:51:07 +00005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <console/console.h>
21#include <arch/io.h>
22#include <stdint.h>
23#include <device/device.h>
24#include <device/pci.h>
25#include <device/pci_ids.h>
26#include <device/hypertransport.h>
27#include <stdlib.h>
28#include <string.h>
29#include <bitops.h>
30#include <cpu/cpu.h>
Stefan Reinauer71a3d962009-07-21 21:44:24 +000031#include <boot/tables.h>
Stefan Reinauer278534d2008-10-29 04:51:07 +000032#include "chip.h"
33#include "i945.h"
34
Stefan Reinauer71a3d962009-07-21 21:44:24 +000035int get_pcie_bar(u32 *base, u32 *len)
36{
37 device_t dev;
38 u32 pciexbar_reg;
39
40 *base = 0;
41 *len = 0;
42
43 dev = dev_find_slot(0, PCI_DEVFN(0, 0));
44 if (!dev)
45 return 0;
Stefan Reinauer109ab312009-08-12 16:08:05 +000046
Stefan Reinauer71a3d962009-07-21 21:44:24 +000047 pciexbar_reg = pci_read_config32(dev, 0x48);
48
49 if (!(pciexbar_reg & (1 << 0)))
50 return 0;
51
52 switch ((pciexbar_reg >> 1) & 3) {
53 case 0: // 256MB
54 *base = pciexbar_reg & ((1 << 31)|(1 << 30)|(1 << 29)|(1 << 28));
55 *len = 256 * 1024 * 1024;
56 return 1;
57 case 1: // 128M
58 *base = pciexbar_reg & ((1 << 31)|(1 << 30)|(1 << 29)|(1 << 28)|(1 << 27));
59 *len = 128 * 1024 * 1024;
60 return 1;
61 case 2: // 64M
62 *base = pciexbar_reg & ((1 << 31)|(1 << 30)|(1 << 29)|(1 << 28)|(1 << 27)|(1 << 26));
63 *len = 64 * 1024 * 1024;
64 return 1;
65 }
66
67 return 0;
68}
69
70/* in arch/i386/boot/tables.c */
71extern uint64_t high_tables_base, high_tables_size;
72
73/* IDG memory */
74uint64_t uma_memory_base=0, uma_memory_size=0;
75
76int add_northbridge_resources(struct lb_memory *mem)
77{
78 u32 pcie_config_base, pcie_config_size;
79
80 printk_debug("Adding UMA memory area\n");
Stefan Reinauer109ab312009-08-12 16:08:05 +000081 lb_add_memory_range(mem, LB_MEM_RESERVED,
Stefan Reinauer71a3d962009-07-21 21:44:24 +000082 uma_memory_base, uma_memory_size);
83
84 printk_debug("Adding PCIe config bar\n");
85 get_pcie_bar(&pcie_config_base, &pcie_config_size);
Stefan Reinauer109ab312009-08-12 16:08:05 +000086 lb_add_memory_range(mem, LB_MEM_RESERVED,
Stefan Reinauer71a3d962009-07-21 21:44:24 +000087 pcie_config_base, pcie_config_size);
88
89 return 0;
90}
91
Stefan Reinauer278534d2008-10-29 04:51:07 +000092static void ram_resource(device_t dev, unsigned long index, unsigned long basek,
93 unsigned long sizek)
94{
95 struct resource *resource;
96
97 resource = new_resource(dev, index);
98 resource->base = ((resource_t) basek) << 10;
99 resource->size = ((resource_t) sizek) << 10;
100 resource->flags = IORESOURCE_MEM | IORESOURCE_CACHEABLE |
101 IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
102}
103
Stefan Reinauer278534d2008-10-29 04:51:07 +0000104static void tolm_test(void *gp, struct device *dev, struct resource *new)
105{
106 struct resource **best_p = gp;
107 struct resource *best;
108 best = *best_p;
109 if (!best || (best->base > new->base)) {
110 best = new;
111 }
112 *best_p = best;
113}
114
115static uint32_t find_pci_tolm(struct bus *bus)
116{
117 struct resource *min;
118 uint32_t tolm;
119 min = 0;
120 search_bus_resources(bus, IORESOURCE_MEM, IORESOURCE_MEM, tolm_test,
121 &min);
122 tolm = 0xffffffffUL;
123 if (min && tolm > min->base) {
124 tolm = min->base;
125 }
126 return tolm;
127}
128
Stefan Reinauer08670622009-06-30 15:17:49 +0000129#if CONFIG_HAVE_HIGH_TABLES==1
Stefan Reinauer3c7f46b2009-02-27 23:09:55 +0000130#define HIGH_TABLES_SIZE 64 // maximum size of high tables in KB
131extern uint64_t high_tables_base, high_tables_size;
132#endif
Stefan Reinauer3c7f46b2009-02-27 23:09:55 +0000133
Stefan Reinauer278534d2008-10-29 04:51:07 +0000134static void pci_domain_set_resources(device_t dev)
135{
136 uint32_t pci_tolm;
137 uint8_t tolud, reg8;
138 uint16_t reg16;
Stefan Reinauer3c7f46b2009-02-27 23:09:55 +0000139 unsigned long long tomk;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000140
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000141 /* Can we find out how much memory we can use at most
142 * this way?
143 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000144 pci_tolm = find_pci_tolm(&dev->link[0]);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000145 printk_debug("pci_tolm: 0x%x\n", pci_tolm);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000146
147 printk_spew("Base of stolen memory: 0x%08x\n",
148 pci_read_config32(dev_find_slot(0, PCI_DEVFN(2, 0)), 0x5c));
149
150 tolud = pci_read_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), 0x9c);
151 printk_spew("Top of Low Used DRAM: 0x%08x\n", tolud << 24);
152
153 tomk = tolud << 14;
154
155 /* Note: subtract IGD device and TSEG */
156 reg8 = pci_read_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), 0x9e);
157 if (reg8 & 1) {
158 int tseg_size = 0;
159 printk_debug("TSEG decoded, subtracting ");
160 reg8 >>= 1;
161 reg8 &= 3;
162 switch (reg8) {
163 case 0:
164 tseg_size = 1024;
Stefan Reinauer3c7f46b2009-02-27 23:09:55 +0000165 break; /* TSEG = 1M */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000166 case 1:
167 tseg_size = 2048;
Stefan Reinauer3c7f46b2009-02-27 23:09:55 +0000168 break; /* TSEG = 2M */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000169 case 2:
170 tseg_size = 8192;
Stefan Reinauer3c7f46b2009-02-27 23:09:55 +0000171 break; /* TSEG = 8M */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000172 }
173
174 printk_debug("%dM\n", tseg_size >> 10);
175 tomk -= tseg_size;
176 }
177
178 reg16 = pci_read_config16(dev_find_slot(0, PCI_DEVFN(0, 0)), GGC);
179 if (!(reg16 & 2)) {
180 int uma_size = 0;
181 printk_debug("IGD decoded, subtracting ");
182 reg16 >>= 4;
183 reg16 &= 7;
184 switch (reg16) {
185 case 1:
186 uma_size = 1024;
187 break;
188 case 3:
189 uma_size = 8192;
190 break;
191 }
192
193 printk_debug("%dM UMA\n", uma_size >> 10);
194 tomk -= uma_size;
Stefan Reinauer3c7f46b2009-02-27 23:09:55 +0000195
196 /* For reserving UMA memory in the memory map */
197 uma_memory_base = tomk * 1024ULL;
198 uma_memory_size = uma_size * 1024ULL;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000199 }
200
201 /* The following needs to be 2 lines, otherwise the second
202 * number is always 0
203 */
Stefan Reinauer3c7f46b2009-02-27 23:09:55 +0000204 printk_info("Available memory: %dK", (uint32_t)tomk);
205 printk_info(" (%dM)\n", (uint32_t)(tomk >> 10));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000206
207 /* Report the memory regions */
208 ram_resource(dev, 3, 0, 640);
Stefan Reinauer3c7f46b2009-02-27 23:09:55 +0000209 ram_resource(dev, 4, 768, (tomk - 768));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000210 if (tomk > 4 * 1024 * 1024) {
211 ram_resource(dev, 5, 4096 * 1024, tomk - 4 * 1024 * 1024);
212 }
213
214 assign_resources(&dev->link[0]);
Stefan Reinauer3c7f46b2009-02-27 23:09:55 +0000215
Stefan Reinauer08670622009-06-30 15:17:49 +0000216#if CONFIG_HAVE_HIGH_TABLES==1
Stefan Reinauer3c7f46b2009-02-27 23:09:55 +0000217 /* Leave some space for ACPI, PIRQ and MP tables */
218 high_tables_base = (tomk - HIGH_TABLES_SIZE) * 1024;
219 high_tables_size = HIGH_TABLES_SIZE * 1024;
220#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +0000221}
222
Stefan Reinauer278534d2008-10-29 04:51:07 +0000223 /* TODO We could determine how many PCIe busses we need in
224 * the bar. For now that number is hardcoded to a max of 64.
Myles Watson29cc9ed2009-07-02 18:56:24 +0000225 * See e7525/northbridge.c for an example.
Stefan Reinauer278534d2008-10-29 04:51:07 +0000226 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000227static struct device_operations pci_domain_ops = {
228 .read_resources = pci_domain_read_resources,
229 .set_resources = pci_domain_set_resources,
230 .enable_resources = enable_childrens_resources,
231 .init = 0,
232 .scan_bus = pci_domain_scan_bus,
Stefan Reinauer08670622009-06-30 15:17:49 +0000233#if CONFIG_MMCONF_SUPPORT_DEFAULT
Stefan Reinauer43b29cf2009-03-06 19:11:52 +0000234 .ops_pci_bus = &pci_ops_mmconf,
235#else
236 .ops_pci_bus = &pci_cf8_conf1,
237#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +0000238};
239
240static void mc_read_resources(device_t dev)
241{
242 struct resource *resource;
243
244 pci_dev_read_resources(dev);
245
246 /* So, this is one of the big mysteries in the coreboot resource
247 * allocator. This resource should make sure that the address space
248 * of the PCIe memory mapped config space bar. But it does not.
249 */
250
251 /* We use 0xcf as an unused index for our PCIe bar so that we find it again */
252 resource = new_resource(dev, 0xcf);
253 resource->base = DEFAULT_PCIEXBAR;
254 resource->size = 64 * 1024 * 1024; /* 64MB hard coded PCIe config space */
255 resource->flags =
256 IORESOURCE_MEM | IORESOURCE_FIXED | IORESOURCE_STORED |
257 IORESOURCE_ASSIGNED;
Stefan Reinauer30140a52009-03-11 16:20:39 +0000258 printk_debug("Adding PCIe enhanced config space BAR 0x%08lx-0x%08lx.\n",
259 (unsigned long)(resource->base), (unsigned long)(resource->base + resource->size));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000260}
261
262static void mc_set_resources(device_t dev)
263{
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000264 struct resource *resource;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000265
266 /* Report the PCIe BAR */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000267 resource = find_resource(dev, 0xcf);
268 if (resource) {
269 report_resource_stored(dev, resource, "<mmconfig>");
270 }
271
272 /* And call the normal set_resources */
273 pci_dev_set_resources(dev);
274}
275
276static void intel_set_subsystem(device_t dev, unsigned vendor, unsigned device)
277{
Stefan Reinauer30140a52009-03-11 16:20:39 +0000278 if (!vendor || !device) {
279 pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
280 pci_read_config32(dev, PCI_VENDOR_ID));
281 } else {
282 pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
283 ((device & 0xffff) << 16) | (vendor & 0xffff));
284 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000285}
286
287static struct pci_operations intel_pci_ops = {
288 .set_subsystem = intel_set_subsystem,
289};
290
291static struct device_operations mc_ops = {
292 .read_resources = mc_read_resources,
293 .set_resources = mc_set_resources,
294 .enable_resources = pci_dev_enable_resources,
295 .init = 0,
296 .scan_bus = 0,
297 .ops_pci = &intel_pci_ops,
298};
299
300static const struct pci_driver mc_driver __pci_driver = {
301 .ops = &mc_ops,
302 .vendor = PCI_VENDOR_ID_INTEL,
Uwe Hermann5d7a1c82008-10-31 18:41:09 +0000303 .device = 0x27a0,
Stefan Reinauer278534d2008-10-29 04:51:07 +0000304};
305
306static void cpu_bus_init(device_t dev)
307{
308 initialize_cpus(&dev->link[0]);
309}
310
311static void cpu_bus_noop(device_t dev)
312{
313}
314
315static struct device_operations cpu_bus_ops = {
316 .read_resources = cpu_bus_noop,
317 .set_resources = cpu_bus_noop,
318 .enable_resources = cpu_bus_noop,
319 .init = cpu_bus_init,
320 .scan_bus = 0,
321};
322
323static void enable_dev(device_t dev)
324{
325 /* Set the operations if it is a special bus type */
326 if (dev->path.type == DEVICE_PATH_PCI_DOMAIN) {
327 dev->ops = &pci_domain_ops;
328 } else if (dev->path.type == DEVICE_PATH_APIC_CLUSTER) {
329 dev->ops = &cpu_bus_ops;
330 }
331}
332
333struct chip_operations northbridge_intel_i945_ops = {
334 CHIP_NAME("Intel i945 Northbridge")
335 .enable_dev = enable_dev,
336};