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