| /* |
| * This file is part of the coreboot project. |
| * |
| * Copyright (C) 2015 Intel Corp. |
| * (Written by Andrey Petrov <andrey.petrov@intel.com> for Intel Corp.) |
| * (Written by Alexandru Gagniuc <alexandrux.gagniuc@intel.com> for Intel Corp.) |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| */ |
| |
| #include <console/console.h> |
| #include <soc/iomap.h> |
| #include <device/pci.h> |
| #include <device/pci_ids.h> |
| #include <soc/northbridge.h> |
| #include <soc/pci_ids.h> |
| |
| static uint32_t get_bar(device_t dev, unsigned int index) |
| { |
| uint32_t bar; |
| |
| bar = pci_read_config32(dev, index); |
| |
| /* If not enabled return 0 else strip enabled bit */ |
| return (bar & 1) ? (bar & ~1) : 0; |
| } |
| |
| static int mc_add_fixed_mmio_resources(device_t dev, int index) |
| { |
| unsigned long addr; |
| |
| /* PCI extended config region */ |
| addr = ALIGN_DOWN(get_bar(dev, PCIEXBAR), 256*MiB) / KiB; |
| mmio_resource(dev, index++, addr, PCIEX_SIZE / KiB); |
| |
| /* Memory Controller Hub */ |
| addr = ALIGN_DOWN(get_bar(dev, MCHBAR), 32*KiB) / KiB; |
| mmio_resource(dev, index++, addr, MCH_BASE_SIZE / KiB); |
| |
| return index; |
| } |
| |
| static bool is_imr_enabled(uint32_t imr_base_reg) |
| { |
| return !!(imr_base_reg & (1 << 31)); |
| } |
| |
| static void imr_resource(device_t dev, int idx, uint32_t base, uint32_t mask) |
| { |
| uint32_t base_k, size_k; |
| /* Bits 28:0 encode the base address bits 38:10, hence the KiB unit. */ |
| base_k = (base & 0x0fffffff); |
| /* Bits 28:0 encode the AND mask used for comparison, in KiB. */ |
| size_k = ((~mask & 0x0fffffff) + 1); |
| /* |
| * IMRs sit in lower DRAM. Mark them cacheable, otherwise we run |
| * out of MTRRs. Memory reserved by IMRs is not usable for host |
| * so mark it reserved. |
| */ |
| reserved_ram_resource(dev, idx, base_k, size_k); |
| } |
| |
| static int mc_add_imr_resources(device_t dev, int index) |
| { |
| uint8_t *mchbar; |
| size_t i, imr_offset; |
| uint32_t base, mask; |
| |
| mchbar = (void *)(ALIGN_DOWN(get_bar(dev, MCHBAR), 32*KiB)); |
| |
| for (i = 0; i < MCH_NUM_IMRS; i++) { |
| imr_offset = i * MCH_IMR_PITCH; |
| base = read32(mchbar + imr_offset + MCHBAR_IMR0BASE); |
| mask = read32(mchbar + imr_offset + MCHBAR_IMR0MASK); |
| |
| if (is_imr_enabled(base)) { |
| imr_resource(dev, index++, base, mask); |
| } |
| } |
| |
| return index; |
| } |
| |
| |
| static int mc_add_dram_resources(device_t dev, int index) |
| { |
| unsigned long base_k, size_k; |
| uint32_t bgsm, bdsm, tolud, tseg; |
| uint64_t touud; |
| |
| bgsm = ALIGN_DOWN(pci_read_config32(dev, BGSM), MiB); |
| bdsm = ALIGN_DOWN(pci_read_config32(dev, BDSM), MiB); |
| tolud = ALIGN_DOWN(pci_read_config32(dev, TOLUD), MiB); |
| tseg = ALIGN_DOWN(pci_read_config32(dev, TSEG), MiB); |
| |
| /* TOUUD is naturally a 64 bit integer */ |
| touud = pci_read_config32(dev, TOUUD + sizeof(uint32_t)); |
| touud <<= 32; |
| touud |= ALIGN_DOWN(pci_read_config32(dev, TOUUD), MiB); |
| |
| /* 0 - > 0xa0000: 640kb of DOS memory. Not enough for anybody nowadays */ |
| ram_resource(dev, index++, 0, 640); |
| |
| /* 0xa0000 - 0xbffff: legacy VGA */ |
| mmio_resource(dev, index++, 640, 128); |
| |
| /* 0xc0000 -> 0xfffff: leave without e820 entry, as it has special uses */ |
| /* 0x100000 -> top_of_ram */ |
| base_k = 1024; |
| size_k = (tseg / KiB) - base_k; |
| ram_resource(dev, index++, base_k, size_k); |
| |
| /* TSEG -> BGSM */ |
| reserved_ram_resource(dev, index++, tseg / KiB, (bgsm - tseg) / KiB); |
| |
| /* BGSM -> BDSM */ |
| mmio_resource(dev, index++, bgsm / KiB, (bdsm - bgsm) / KiB); |
| |
| /* BDSM -> TOLUD */ |
| mmio_resource(dev, index++, bdsm / KiB, (tolud - bdsm) / KiB); |
| |
| /* 4G -> TOUUD */ |
| base_k = 4ULL*GiB / KiB; |
| size_k = (touud / KiB) - base_k; |
| ram_resource(dev, index++, base_k, size_k); |
| |
| |
| return index; |
| } |
| |
| static void northbridge_read_resources(device_t dev) |
| { |
| |
| int index = 0; |
| /* Read standard PCI resources. */ |
| pci_dev_read_resources(dev); |
| |
| /* Add all fixed MMIO resources. */ |
| index = mc_add_fixed_mmio_resources(dev, index); |
| |
| /* Calculate and add DRAM resources. */ |
| index = mc_add_dram_resources(dev, index); |
| |
| /* Add the isolated memory ranges (IMRs). */ |
| mc_add_imr_resources(dev, index); |
| |
| } |
| |
| static struct device_operations northbridge_ops = { |
| .read_resources = northbridge_read_resources, |
| .set_resources = pci_dev_set_resources, |
| .enable_resources = pci_dev_enable_resources, |
| .init = DEVICE_NOOP, |
| .enable = DEVICE_NOOP |
| }; |
| |
| static const struct pci_driver northbridge_driver __pci_driver = { |
| .ops = &northbridge_ops, |
| .vendor = PCI_VENDOR_ID_INTEL, |
| .device = PCI_DEVICE_ID_APOLLOLAKE_NB |
| }; |