/*
 * 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
};
