source: trunk/src/northbridge/intel/i945/northbridge.c

Last change on this file was 6171, checked in by ruik, 2 years ago

We hardcode highmemory size in every northbridge! This is bad, and especially if suspend to ram is involved. Let the default be taken from cbmem.h which also handles the suspend logic.

Abuild tested. Please check all changes if I did not make any wrong while converting this to bytes.

Signed-off-by: Rudolf Marek <r.marek@…>
Acked-by: Peter Stuge <peter@…>

File size: 8.5 KB
Line 
1/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2007-2009 coresystems GmbH
5 *
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>
31#include <boot/tables.h>
32#include "chip.h"
33#include "i945.h"
34
35static int 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;
46
47        pciexbar_reg = pci_read_config32(dev, PCIEXBAR);
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/* IDG memory */
71uint64_t uma_memory_base=0, uma_memory_size=0;
72
73static void add_fixed_resources(struct device *dev, int index)
74{
75        struct resource *resource;
76        u32 pcie_config_base, pcie_config_size;
77
78        printk(BIOS_DEBUG, "Adding UMA memory area\n");
79        resource = new_resource(dev, index);
80        resource->base = (resource_t) uma_memory_base;
81        resource->size = (resource_t) uma_memory_size;
82        resource->flags = IORESOURCE_MEM | IORESOURCE_RESERVE |
83            IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
84
85        if (get_pcie_bar(&pcie_config_base, &pcie_config_size)) {
86                printk(BIOS_DEBUG, "Adding PCIe config bar\n");
87                resource = new_resource(dev, index+1);
88                resource->base = (resource_t) pcie_config_base;
89                resource->size = (resource_t) pcie_config_size;
90                resource->flags = IORESOURCE_MEM | IORESOURCE_RESERVE |
91                    IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
92        }
93}
94
95#if CONFIG_WRITE_HIGH_TABLES==1
96#include <cbmem.h>
97#endif
98
99static void pci_domain_set_resources(device_t dev)
100{
101        uint32_t pci_tolm;
102        uint8_t tolud, reg8;
103        uint16_t reg16;
104        unsigned long long tomk;
105
106        /* Can we find out how much memory we can use at most
107         * this way?
108         */
109        pci_tolm = find_pci_tolm(dev->link_list);
110        printk(BIOS_DEBUG, "pci_tolm: 0x%x\n", pci_tolm);
111
112        printk(BIOS_SPEW, "Base of stolen memory: 0x%08x\n",
113                    pci_read_config32(dev_find_slot(0, PCI_DEVFN(2, 0)), 0x5c));
114
115        tolud = pci_read_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), 0x9c);
116        printk(BIOS_SPEW, "Top of Low Used DRAM: 0x%08x\n", tolud << 24);
117
118        tomk = tolud << 14;
119
120        /* Note: subtract IGD device and TSEG */
121        reg8 = pci_read_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), 0x9e);
122        if (reg8 & 1) {
123                int tseg_size = 0;
124                printk(BIOS_DEBUG, "TSEG decoded, subtracting ");
125                reg8 >>= 1;
126                reg8 &= 3;
127                switch (reg8) {
128                case 0:
129                        tseg_size = 1024;
130                        break;  /* TSEG = 1M */
131                case 1:
132                        tseg_size = 2048;
133                        break;  /* TSEG = 2M */
134                case 2:
135                        tseg_size = 8192;
136                        break;  /* TSEG = 8M */
137                }
138
139                printk(BIOS_DEBUG, "%dM\n", tseg_size >> 10);
140                tomk -= tseg_size;
141        }
142
143        reg16 = pci_read_config16(dev_find_slot(0, PCI_DEVFN(0, 0)), GGC);
144        if (!(reg16 & 2)) {
145                int uma_size = 0;
146                printk(BIOS_DEBUG, "IGD decoded, subtracting ");
147                reg16 >>= 4;
148                reg16 &= 7;
149                switch (reg16) {
150                case 1:
151                        uma_size = 1024;
152                        break;
153                case 3:
154                        uma_size = 8192;
155                        break;
156                }
157
158                printk(BIOS_DEBUG, "%dM UMA\n", uma_size >> 10);
159                tomk -= uma_size;
160
161                /* For reserving UMA memory in the memory map */
162                uma_memory_base = tomk * 1024ULL;
163                uma_memory_size = uma_size * 1024ULL;
164        }
165
166        /* The following needs to be 2 lines, otherwise the second
167         * number is always 0
168         */
169        printk(BIOS_INFO, "Available memory: %dK", (uint32_t)tomk);
170        printk(BIOS_INFO, " (%dM)\n", (uint32_t)(tomk >> 10));
171
172        /* Report the memory regions */
173        ram_resource(dev, 3, 0, 640);
174        ram_resource(dev, 4, 768, (tomk - 768));
175        if (tomk > 4 * 1024 * 1024) {
176                ram_resource(dev, 5, 4096 * 1024, tomk - 4 * 1024 * 1024);
177        }
178
179        add_fixed_resources(dev, 6);
180
181        assign_resources(dev->link_list);
182
183#if CONFIG_WRITE_HIGH_TABLES==1
184        /* Leave some space for ACPI, PIRQ and MP tables */
185        high_tables_base = (tomk * 1024) - HIGH_MEMORY_SIZE;
186        high_tables_size = HIGH_MEMORY_SIZE;
187#endif
188}
189
190        /* TODO We could determine how many PCIe busses we need in
191         * the bar. For now that number is hardcoded to a max of 64.
192         * See e7525/northbridge.c for an example.
193         */
194static struct device_operations pci_domain_ops = {
195        .read_resources   = pci_domain_read_resources,
196        .set_resources    = pci_domain_set_resources,
197        .enable_resources = NULL,
198        .init             = NULL,
199        .scan_bus         = pci_domain_scan_bus,
200#if CONFIG_MMCONF_SUPPORT_DEFAULT
201        .ops_pci_bus      = &pci_ops_mmconf,
202#else
203        .ops_pci_bus      = &pci_cf8_conf1,
204#endif
205};
206
207static void mc_read_resources(device_t dev)
208{
209        struct resource *resource;
210
211        pci_dev_read_resources(dev);
212
213        /* So, this is one of the big mysteries in the coreboot resource
214         * allocator. This resource should make sure that the address space
215         * of the PCIe memory mapped config space bar. But it does not.
216         */
217
218        /* We use 0xcf as an unused index for our PCIe bar so that we find it again */
219        resource = new_resource(dev, 0xcf);
220        resource->base = DEFAULT_PCIEXBAR;
221        resource->size = 64 * 1024 * 1024;      /* 64MB hard coded PCIe config space */
222        resource->flags =
223            IORESOURCE_MEM | IORESOURCE_FIXED | IORESOURCE_STORED |
224            IORESOURCE_ASSIGNED;
225        printk(BIOS_DEBUG, "Adding PCIe enhanced config space BAR 0x%08lx-0x%08lx.\n",
226                     (unsigned long)(resource->base), (unsigned long)(resource->base + resource->size));
227}
228
229static void mc_set_resources(device_t dev)
230{
231        struct resource *resource;
232
233        /* Report the PCIe BAR */
234        resource = find_resource(dev, 0xcf);
235        if (resource) {
236                report_resource_stored(dev, resource, "<mmconfig>");
237        }
238
239        /* And call the normal set_resources */
240        pci_dev_set_resources(dev);
241}
242
243static void intel_set_subsystem(device_t dev, unsigned vendor, unsigned device)
244{
245        if (!vendor || !device) {
246                pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
247                                pci_read_config32(dev, PCI_VENDOR_ID));
248        } else {
249                pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
250                                ((device & 0xffff) << 16) | (vendor & 0xffff));
251        }
252}
253
254#if CONFIG_HAVE_ACPI_RESUME
255extern u8 acpi_slp_type;
256
257static void northbridge_init(struct device *dev)
258{
259        switch (pci_read_config32(dev, SKPAD)) {
260        case 0xcafebabe:
261                printk(BIOS_DEBUG, "Normal boot.\n");
262                acpi_slp_type=0;
263                break;
264        case 0xcafed00d:
265                printk(BIOS_DEBUG, "S3 Resume.\n");
266                acpi_slp_type=3;
267                break;
268        default:
269                printk(BIOS_DEBUG, "Unknown boot method, assuming normal.\n");
270                acpi_slp_type=0;
271                break;
272        }
273}
274#endif
275
276static struct pci_operations intel_pci_ops = {
277        .set_subsystem    = intel_set_subsystem,
278};
279
280static struct device_operations mc_ops = {
281        .read_resources   = mc_read_resources,
282        .set_resources    = mc_set_resources,
283        .enable_resources = pci_dev_enable_resources,
284#if CONFIG_HAVE_ACPI_RESUME
285        .init             = northbridge_init,
286#endif
287        .scan_bus         = 0,
288        .ops_pci          = &intel_pci_ops,
289};
290
291static const struct pci_driver mc_driver __pci_driver = {
292        .ops    = &mc_ops,
293        .vendor = PCI_VENDOR_ID_INTEL,
294        .device = 0x27a0,
295};
296
297static void cpu_bus_init(device_t dev)
298{
299        initialize_cpus(dev->link_list);
300}
301
302static void cpu_bus_noop(device_t dev)
303{
304}
305
306static struct device_operations cpu_bus_ops = {
307        .read_resources   = cpu_bus_noop,
308        .set_resources    = cpu_bus_noop,
309        .enable_resources = cpu_bus_noop,
310        .init             = cpu_bus_init,
311        .scan_bus         = 0,
312};
313
314static void enable_dev(device_t dev)
315{
316        /* Set the operations if it is a special bus type */
317        if (dev->path.type == DEVICE_PATH_PCI_DOMAIN) {
318                dev->ops = &pci_domain_ops;
319        } else if (dev->path.type == DEVICE_PATH_APIC_CLUSTER) {
320                dev->ops = &cpu_bus_ops;
321        }
322}
323
324struct chip_operations northbridge_intel_i945_ops = {
325        CHIP_NAME("Intel i945 Northbridge")
326        .enable_dev = enable_dev,
327};
Note: See TracBrowser for help on using the repository browser.