/*
 * This file is part of the coreboot project.
 * Copyright (C) 2019 Philipp Hug <philipp@hug.dev>
 *
 * 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; version 2 of the License.
 *
 * 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 <stdint.h>
#include <string.h>
#include <lib.h>

#include <arch/byteorder.h>
#include <cbfs.h>
#include <console/console.h>
#include <northbridge/intel/sandybridge/raminit_native.h>
#include <device/pci.h>
#include <device/pci_def.h>
#include <southbridge/intel/bd82x6x/pch.h>
#include <southbridge/intel/bd82x6x/pch.h>

// void mainboard_get_spd(spd_raw_data *spd, bool id_only)
// {
//         uint8_t *spd_file;
//         size_t spd_file_len;
// 
//         spd_file = cbfs_boot_map_with_leak("spd.bin", CBFS_TYPE_SPD,
//                                                 &spd_file_len);
//         if (!spd_file)
//                 die("SPD data not found.");
// 
//         if (spd_file_len < 256)
//                 die("Missing SPD data.");
// 
// 	//memcpy(&spd[0], spd_file, 256);
// 	memcpy(&spd[1], spd_file, 256);
// 	//memcpy(&spd[2], spd_file, 256);
// 	//memcpy(&spd[3], spd_file, 256);
// 
// /* try to read it from the bus */
// //read_spd (&spd[0], 0x50, id_only);
// //read_spd (&spd[1], 0x51, id_only);
// //read_spd (&spd[2], 0x52, id_only);
// //read_spd (&spd[3], 0x53, id_only);
// }

void mainboard_early_init(int s3reumse)
{
	u32 ilo0_base = 0x1000;
	u32 ilo2_base = 0x1400;

	pci_devfn_t dev = PCI_DEV(0, 31, 0);
        pci_devfn_t bridge = PCI_DEV(0, 0x1c, 7);
        uintptr_t rcba; /* Root Complex Register Block */
        void *spibase;


        /* Setup base address on bridge */
        pci_write_config32(bridge, PCI_PRIMARY_BUS, 0x10100);
        pci_write_config32(bridge, PCI_IO_BASE, 0x1010); //0x1000-0x1fff

        /* Enable I/O on bridge */
        u16 reg16 = pci_read_config16(bridge, PCI_COMMAND);
        reg16 |= PCI_COMMAND_IO;
        pci_write_config16(bridge, PCI_COMMAND, reg16);


        pci_devfn_t device = PCI_DEV(1, 0, 0);

        u32 id = pci_read_config32(device, PCI_VENDOR_ID);
        switch (id) {
        case 0x3306103c: /* HP Proliant ILO */
                break;
        default:
		printk(BIOS_DEBUG, "wrong device: 0x%x\n", id);
                /* No ILO here. */
                //return -1;
        }

        /* Setup base address on device */
        pci_write_config32(device, PCI_BASE_ADDRESS_0, ilo0_base);
        pci_write_config32(device, PCI_BASE_ADDRESS_2, ilo2_base);

        /* Enable I/O on device */
        reg16 = pci_read_config16(device, PCI_COMMAND);
        reg16 |= PCI_COMMAND_IO;
        pci_write_config16(device, PCI_COMMAND, reg16);

	/* Write 0x10 to register 0xb0 of PCI device 01:00.0 */
	outb(0x10, 0x10b0);

	u32 first = pci_read_config32(PCI_DEVFN(0, 0), CAPID0_A);
	printk(BIOS_ERR, "Reading CAPID0_A first %x\n", first);

	/* lets try to rewrite ECC */
	u32 reg32 = pci_read_config32(PCI_DEVFN(0, 0), CAPID0_A);
	reg32 |= (1 << 24);
	reg32 |= (1 << 25);
	pci_write_config32(PCI_DEVFN(0, 0), CAPID0_A, reg32);

	u32 back = pci_read_config32(PCI_DEVFN(0, 0), CAPID0_A);
	printk(BIOS_ERR, "Reading CAPID0_A back %x\n", back);

	/* check if cpu is configured correctly */
        rcba = pci_read_config32(dev, RCBA);
	spibase = (void *)((rcba & 0xffffc000) + 0x3800);

	/* clear Set Stap Lock */
	clrbits32(spibase + 0xf0, BIT(0));
	write32(spibase + 0xf8, 0x000005c5);

	/* enable our CPU configuration */
	setbits32(spibase + 0xf4, BIT(0));

	/* set Set Stap Lock */
	setbits32(spibase + 0xf0, BIT(0));


	printk(BIOS_ERR, "resetting\n");
        u32 etr3 = pci_read_config32(PCH_LPC_DEV, ETR3);

        /* Clear CF9 Without Resume Well Reset Enable */
        etr3 &= ~ETR3_CWORWRE;

        /* CF9GR indicates a Global Reset */
        if (0)
                etr3 |= ETR3_CF9GR;
        else
                etr3 &= ~ETR3_CF9GR;

        pci_write_config32(PCH_LPC_DEV, ETR3, etr3);

        outb(0x0, 0xcf9);
        outb(0x6, 0xcf9);
	halt();
}

void mainboard_get_spd(spd_raw_data *spd, bool id_only)
{
	/* try to read it from the bus */
	read_spd (&spd[0], 0x50, id_only);
	read_spd (&spd[1], 0x51, id_only);
	read_spd (&spd[2], 0x52, id_only);
	read_spd (&spd[3], 0x53, id_only);

	for(int i=0; i< 4 ; i++) {
		printk(BIOS_ERR, "Hexdumping spd %d\n", i);
		hexdump(&spd[i], 256);
	}
}
