94 changes: 94 additions & 0 deletions src/mainboard/pcengines/apu5/dsdt.asl
@@ -0,0 +1,94 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2013 Advanced Micro Devices, Inc.
* Copyright (C) 2013 Sage Electronic Engineering, LLC
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

/* DefinitionBlock Statement */
DefinitionBlock (
"DSDT.AML", /* Output filename */
"DSDT", /* Signature */
0x02, /* DSDT Revision, needs to be 2 for 64bit */
"AMD ", /* OEMID */
"COREBOOT", /* TABLE ID */
0x00010001 /* OEM Revision */
)
{ /* Start of ASL file */
/* #include <arch/x86/acpi/debug.asl> */ /* Include global debug methods if needed */

/* Globals for the platform */
#include "acpi/mainboard.asl"

/* Describe the USB Overcurrent pins */
#include "acpi/usb_oc.asl"

/* PCI IRQ mapping for the Southbridge */
#include <southbridge/amd/pi/hudson/acpi/pcie.asl>

/* Describe the processor tree (\_PR) */
#include <cpu/amd/pi/00730F01/acpi/cpu.asl>

/* Contains the supported sleep states for this chipset */
#include <southbridge/amd/pi/hudson/acpi/sleepstates.asl>

/* Contains the Sleep methods (WAK, PTS, GTS, etc.) */
#include "acpi/sleep.asl"

/* System Bus */
Scope(\_SB) { /* Start \_SB scope */
/* global utility methods expected within the \_SB scope */
#include <arch/x86/acpi/globutil.asl>

/* Describe IRQ Routing mapping for this platform (within the \_SB scope) */
#include "acpi/routing.asl"

Device(PWRB) {
Name(_HID, EISAID("PNP0C0C"))
Name(_UID, 0xAA)
Name(_PRW, Package () {3, 0x04})
Name(_STA, 0x0B)
}

Device(PCI0) {
/* Describe the AMD Northbridge */
#include <northbridge/amd/pi/00730F01/acpi/northbridge.asl>

/* Describe the AMD Fusion Controller Hub Southbridge */
#include <southbridge/amd/pi/hudson/acpi/fch.asl>
}

/* Describe PCI INT[A-H] for the Southbridge */
#include "acpi/pci_int.asl"




} /* End \_SB scope */

/* Describe SMBUS for the Southbridge */
#include <southbridge/amd/pi/hudson/acpi/smbus.asl>

/* Define the General Purpose Events for the platform */
#include "acpi/gpe.asl"

/* Define the Thermal zones and methods for the platform */
#include "acpi/thermal.asl"

/* Define the System Indicators for the platform */
#include "acpi/si.asl"
}
/* End of ASL file */
108 changes: 108 additions & 0 deletions src/mainboard/pcengines/apu5/irq_tables.c
@@ -0,0 +1,108 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2012 Advanced Micro Devices, Inc.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <console/console.h>
#include <device/pci.h>
#include <string.h>
#include <stdint.h>
#include <arch/pirq_routing.h>
#include <cpu/amd/amdfam16.h>

static void write_pirq_info(struct irq_info *pirq_info, u8 bus, u8 devfn,
u8 link0, u16 bitmap0, u8 link1, u16 bitmap1,
u8 link2, u16 bitmap2, u8 link3, u16 bitmap3,
u8 slot, u8 rfu)
{
pirq_info->bus = bus;
pirq_info->devfn = devfn;
pirq_info->irq[0].link = link0;
pirq_info->irq[0].bitmap = bitmap0;
pirq_info->irq[1].link = link1;
pirq_info->irq[1].bitmap = bitmap1;
pirq_info->irq[2].link = link2;
pirq_info->irq[2].bitmap = bitmap2;
pirq_info->irq[3].link = link3;
pirq_info->irq[3].bitmap = bitmap3;
pirq_info->slot = slot;
pirq_info->rfu = rfu;
}

#define IRQ_BITMAP 0xdee8 //0xdef8 Removed IRQ 4, this is used for serial

unsigned long write_pirq_routing_table(unsigned long addr)
{
struct irq_routing_table *pirq;
struct irq_info *pirq_info;
u32 slot_num;
u8 *v;

u8 sum = 0;
int i;

/* Align the table to be 16 byte aligned. */
addr += 15;
addr &= ~15;

/* This table must be between 0xf0000 & 0x100000 */
printk(BIOS_INFO, "Writing IRQ routing tables to 0x%lx...", addr);

pirq = (void *)(addr);
v = (u8 *) (addr);

pirq->signature = PIRQ_SIGNATURE;
pirq->version = PIRQ_VERSION;

pirq->rtr_bus = 0;
pirq->rtr_devfn = PCI_DEVFN(0x14, 4);

pirq->exclusive_irqs = 0;

pirq->rtr_vendor = 0x1002;
pirq->rtr_device = 0x4384;

pirq->miniport_data = 0;

memset(pirq->rfu, 0, sizeof(pirq->rfu));

pirq_info = (void *)(&pirq->checksum + 1);
slot_num = 0;

/* pci bridge */
write_pirq_info(pirq_info, 0, PCI_DEVFN(0x14, 4),
0x1, IRQ_BITMAP, 0x2, IRQ_BITMAP, 0x3, IRQ_BITMAP, 0x4, IRQ_BITMAP, 0,
0);
pirq_info++;

slot_num++;

pirq->size = 32 + 16 * slot_num;

for (i = 0; i < pirq->size; i++)
sum += v[i];

sum = pirq->checksum - sum;

if (sum != pirq->checksum) {
pirq->checksum = sum;
}

printk(BIOS_INFO, "write_pirq_routing_table done.\n");

return (unsigned long)pirq_info;
}
231 changes: 231 additions & 0 deletions src/mainboard/pcengines/apu5/mainboard.c
@@ -0,0 +1,231 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2012 Advanced Micro Devices, Inc.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <console/console.h>
#include <device/device.h>
#include <device/pci.h>
#include <arch/io.h>
#include <device/pci_def.h>
#include <arch/acpi.h>
#include <northbridge/amd/pi/BiosCallOuts.h>
#include <cpu/amd/pi/s3_resume.h>
#include <northbridge/amd/pi/agesawrapper.h>
#include <cpu/x86/msr.h>
#include <cpu/amd/mtrr.h>
#if CONFIG_USE_OPTION_TABLE
#include <pc80/mc146818rtc.h>
#endif //CONFIG_USE_OPTION_TABLE
#if CONFIG_HAVE_OPTION_TABLE
#include "option_table.h"
#endif //CONFIG_HAVE_OPTION_TABLE
#include <eltanhudson.h>
#include <timestamp.h>
#include <fchgpio.h>
#include "apu5.h"
#include <superio/nuvoton/nct5104d/nct5104d.h>
#include <northbridge/amd/pi/00730F01/eltannorthbridge.h>
#if CONFIG_USE_CBMEM_FILE_OVERRIDE
#include <boot/cbmemfile.h>
#endif //CONFIG_USE_CBMEM_FILE_OVERRIDE
#include <spd_cache.h>
#include <smbios.h>
#include <string.h>
#include <cpu/amd/amdfam16.h>
#include <cpuRegisters.h>
#include <build.h>
#include "bios_knobs.h"

/**********************************************
* enable the dedicated function in mainboard.
**********************************************/

static void mainboard_enable(device_t dev)
{
struct device *sio_dev;

bool scon = check_console();
setup_bsp_ramtop();
u32 total_mem = bsp_topmem() / (1024 * 1024);
if (bsp_topmem2() > 0)
total_mem += (bsp_topmem2() / (1024 * 1024)) - 4 * 1024;
if (scon) {
printk(BIOS_ALERT, CONFIG_MAINBOARD_PART_NUMBER "\n");
printk(BIOS_ALERT, "coreboot build %s\n", COREBOOT_YYYYMMDD_DATE);
printk(BIOS_ALERT, "BIOS version %s\n", COREBOOT_ORIGIN_GIT_TAG);
printk(BIOS_ALERT, "%d MB", total_mem);
}

u8 spd_buffer[SPD_SIZE];
int index = 0;

/* One SPD file contains all 4 options, determine which index to read here, then call into the standard routines*/

if ( ReadFchGpio(APU5_SPD_STRAP0_GPIO) ) index |= BIT0;
if ( ReadFchGpio(APU5_SPD_STRAP1_GPIO) ) index |= BIT1;

printk(BIOS_SPEW, "Reading SPD index %d to get ECC info \n", index);
if (read_spd_from_cbfs(spd_buffer, index) < 0)
spd_buffer[3]=3; // Indicate no ECC

if (scon) {
if ( spd_buffer[3] == 8 ) printk(BIOS_ALERT, " ECC");
printk(BIOS_ALERT, " DRAM\n\n");
}

//
// Enable the RTC output
//
pm_write16 ( PM_RTC_CONTROL, pm_read16( PM_RTC_CONTROL ) | (1 << 11));

//
// Enable power on from WAKE#
//
pm_write16 ( PM_S_STATE_CONTROL, pm_read16( PM_S_STATE_CONTROL ) | (1 << 14));

if (acpi_is_wakeup_s3())
agesawrapper_fchs3earlyrestore();

//
// SIO CONFIG, enable and disable UARTC and UARTD depending on the configuration
//
if (check_uartc()) {
printk(BIOS_INFO, "UARTC enabled\n");

sio_dev = dev_find_slot_pnp(0x2E, NCT5104D_SP3);
if ( sio_dev ) sio_dev->enabled = 1;
sio_dev = dev_find_slot_pnp(0x2E, NCT5104D_GPIO0);
if ( sio_dev ) sio_dev->enabled = 0;
} else {
printk(BIOS_INFO, "UARTC disabled\n");

sio_dev = dev_find_slot_pnp(0x2E, NCT5104D_SP3);
if ( sio_dev ) sio_dev->enabled = 0;
sio_dev = dev_find_slot_pnp(0x2E, NCT5104D_GPIO0);
if ( sio_dev ) sio_dev->enabled = 1;
}

if (check_uartd()) {
printk(BIOS_INFO, "UARTD enabled\n");

sio_dev = dev_find_slot_pnp(0x2E, NCT5104D_SP4);
if ( sio_dev ) sio_dev->enabled = 1;
sio_dev = dev_find_slot_pnp(0x2E, NCT5104D_GPIO1);
if ( sio_dev ) sio_dev->enabled = 0;
} else {
printk(BIOS_INFO, "UARTD disabled\n");

sio_dev = dev_find_slot_pnp(0x2E, NCT5104D_SP4);
if ( sio_dev ) sio_dev->enabled = 0;
sio_dev = dev_find_slot_pnp(0x2E, NCT5104D_GPIO1);
if ( sio_dev ) sio_dev->enabled = 1;
}
}

static void mainboard_final(void *chip_info) {

printk(BIOS_INFO, "Mainboard " CONFIG_MAINBOARD_PART_NUMBER "final\n");

/* Disabling LPCCLK0 which is unused according to the schematic doesn't work. The system is stuck if we do this
* So we don't do this.
*/

#if CONFIG_DUMP_GPIO_CONFIGURATION
DumpGpioConfiguration( );
#endif //CONFIG_DUMP_GPIO_CONFIGURATION

#if CONFIG_DUMP_CLOCK_CONFIGURATION
DumpClockConfiguration( );
#endif //CONFIG_DUMP_GPIO_CONFIGURATION

#if CONFIG_DUMP_LINK_CONFIGURATION
DumpLinkConfiguration( );
#endif //CONFIG_DUMP_LINK_CONFIGURATION

//
// Turn off LED 2 and 3
//
printk(BIOS_INFO, "Turn off LED 2 and 3\n");
WriteFchGpio( APU5_LED2_L_GPIO, 1);
WriteFchGpio( APU5_LED3_L_GPIO, 1);

printk(BIOS_INFO, "USB PORT ROUTING = 0x%08x\n", *((u8 *)(ACPI_MMIO_BASE + PMIO_BASE + FCH_PMIOA_REGEF )));
if ( *((u8 *)(ACPI_MMIO_BASE + PMIO_BASE + FCH_PMIOA_REGEF )) & (1<<7) ) {

printk(BIOS_INFO, "USB PORT ROUTING = XHCI PORTS ENABLED\n");
} else {

printk(BIOS_INFO, "USB PORT ROUTING = EHCI PORTS ENABLED\n");
}
}

struct chip_operations mainboard_ops = {
.enable_dev = mainboard_enable,
.final = mainboard_final,
};

const char *smbios_mainboard_serial_number(void)
{
static char serial[10];
msr_t msr;
u32 mac_addr = 0;
device_t nic_dev;

// Allows the IO configuration space access method, IOCF8 and IOCFC, to be
// used to generate extended configuration cycles
msr = rdmsr(NB_CFG_MSR);
msr.hi |= (ENABLE_CF8_EXT_CFG);
wrmsr(NB_CFG_MSR, msr);

nic_dev = dev_find_slot(1, PCI_DEVFN(0, 0));

if ((serial[0] != 0) || !nic_dev)
return serial;

// Read 4 bytes starting from 0x144 offset
mac_addr = pci_read_config32(nic_dev, 0x144);
// MSB here is always 0xff
// Discard it so only bottom 3b of mac address are left
mac_addr &= 0x00ffffff;

// Set bit EnableCf8ExtCfg back to 0
msr.hi &= ~(ENABLE_CF8_EXT_CFG);
wrmsr(NB_CFG_MSR, msr);

// Calculate serial value
mac_addr /= 4;
mac_addr -= 64;

snprintf(serial, sizeof(serial), "%d", mac_addr);

return serial;
}

const char *smbios_mainboard_sku(void)
{
static char sku[5];
if (sku[0] != 0)
return sku;

if (!ReadFchGpio(APU5_SPD_STRAP0_GPIO))
snprintf(sku, sizeof(sku), "2 GB");
else
snprintf(sku, sizeof(sku), "4 GB");
return sku;
}
202 changes: 202 additions & 0 deletions src/mainboard/pcengines/apu5/mptable.c
@@ -0,0 +1,202 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2012 Advanced Micro Devices, Inc.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <console/console.h>
#include <arch/smp/mpspec.h>
#include <device/pci.h>
#include <arch/io.h>
#include <arch/ioapic.h>
#include <string.h>
#include <stdint.h>
#include <cpu/amd/amdfam15.h>
#include <arch/cpu.h>
#include <cpu/x86/lapic.h>
//#include <southbridge/amd/agesa/hudson/hudson.h> /* pm_ioread() */
#include <southbridge/amd/pi/hudson/hudson.h> /* pm_ioread() */
#include <southbridge/amd/pi/hudson/amd_pci_int_defs.h> // IRQ routing info


u8 picr_data[FCH_INT_TABLE_SIZE] = {
0x03,0x03,0x05,0x07,0x0B,0x0A,0x1F,0x1F, /* 00 - 07 : INTA - INTF and 2 reserved dont map 4*/
0xFA,0xF1,0x00,0x00,0x1F,0x1F,0x1F,0x1F, /* 08 - 0F */
0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F, /* 10 - 17 */
0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 18 - 1F */
0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x00,0x00, /* 20 - 27 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 28 - 2F */
0x05,0x1F,0x05,0x1F,0x04,0x1F,0x1F,0x1F, /* 30 - 37 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 38 - 3F */
0x1F,0x1F,0x00,0x00,0x00,0x00,0x00,0x00, /* 40 - 47 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 48 - 4F */
// 0x03,0x04,0x05,0x07,0x00,0x00,0x00,0x00, /* 50 - 57 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 50 - 57 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 58 - 5F */
0x00,0x00,0x1F /* 60 - 62 */
};
u8 intr_data[FCH_INT_TABLE_SIZE] = {
0x10,0x10,0x12,0x13,0x14,0x15,0x1F,0x1F, /* 00 - 07 : INTA - INTF and 2 reserved dont map 4*/
0x00,0x00,0x00,0x00,0x1F,0x1F,0x1F,0x1F, /* 08 - 0F */
0x09,0x1F,0x1F,0x1F,0x1F,0x1f,0x1F,0x10, /* 10 - 17 */
0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 18 - 1F */
0x05,0x1F,0x1F,0x1F,0x1F,0x1F,0x00,0x00, /* 20 - 27 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 28 - 2F */
0x12,0x1f,0x12,0x1F,0x12,0x1F,0x1F,0x00, /* 30 - 37 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 38 - 3F */
0x1f,0x13,0x00,0x00,0x00,0x00,0x00,0x00, /* 40 - 47 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 48 - 4F */
// 0x10,0x11,0x12,0x13,0x00,0x00,0x00,0x00, /* 50 - 57 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 50 - 57 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 58 - 5F */
0x00,0x00,0x1F /* 60 - 62 */
};

static void smp_add_mpc_entry(struct mp_config_table *mc, unsigned length)
{
mc->mpc_length += length;
mc->mpc_entry_count++;
}

static void my_smp_write_bus(struct mp_config_table *mc,
unsigned char id, const char *bustype)
{
struct mpc_config_bus *mpc;
mpc = smp_next_mpc_entry(mc);
memset(mpc, '\0', sizeof(*mpc));
mpc->mpc_type = MP_BUS;
mpc->mpc_busid = id;
memcpy(mpc->mpc_bustype, bustype, sizeof(mpc->mpc_bustype));
smp_add_mpc_entry(mc, sizeof(*mpc));
}

static void *smp_write_config_table(void *v)
{
struct mp_config_table *mc;
int bus_isa;
u8 byte;

/*
* By the time this function gets called, the IOAPIC registers
* have been written so they can be read to get the correct
* APIC ID and Version
*/
u8 ioapic_id = (io_apic_read(VIO_APIC_VADDR, 0x00) >> 24);
u8 ioapic_ver = (io_apic_read(VIO_APIC_VADDR, 0x01) & 0xFF);

mc = (void *)(((char *)v) + SMP_FLOATING_TABLE_LEN);

mptable_init(mc, LOCAL_APIC_ADDR);
memcpy(mc->mpc_oem, "AMD ", 8);

smp_write_processors(mc);

//mptable_write_buses(mc, NULL, &bus_isa);
my_smp_write_bus(mc, 0, "PCI ");
my_smp_write_bus(mc, 1, "PCI ");
bus_isa = 0x02;
my_smp_write_bus(mc, bus_isa, "ISA ");

/* I/O APICs: APIC ID Version State Address */
smp_write_ioapic(mc, ioapic_id, ioapic_ver, VIO_APIC_VADDR);

smp_write_ioapic(mc, ioapic_id+1, 0x21, (void *)0xFEC20000);
/* PIC IRQ routine */
for (byte = 0x0; byte < sizeof(picr_data); byte ++) {
outb(byte, 0xC00);
outb(picr_data[byte], 0xC01);
}

/* APIC IRQ routine */
for (byte = 0x0; byte < sizeof(intr_data); byte ++) {
outb(byte | 0x80, 0xC00);
outb(intr_data[byte], 0xC01);
}
/* I/O Ints: Type Polarity Trigger Bus ID IRQ APIC ID PIN# */
#define IO_LOCAL_INT(type, intr, apicid, pin) \
smp_write_lintsrc(mc, (type), MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, bus_isa, (intr), (apicid), (pin));
mptable_add_isa_interrupts(mc, bus_isa, ioapic_id, 0);

/* PCI interrupts are level triggered, and are
* associated with a specific bus/device/function tuple.
*/
#define PCI_INT(bus, dev, int_sign, pin) \
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, (bus), (((dev)<<2)|(int_sign)), ioapic_id, (pin))

/* Internal VGA */
PCI_INT(0x0, 0x01, 0x0, intr_data[PIRQ_B]);
PCI_INT(0x0, 0x01, 0x1, intr_data[PIRQ_C]);

/* SMBUS */
PCI_INT(0x0, 0x14, 0x0, 0x10);

/* HD Audio */
// PCI_INT(0x0, 0x14, 0x0, intr_data[PIRQ_HDA]);

/* SD card */
PCI_INT(0x0, 0x14, 0x1, intr_data[PIRQ_SD]);

/* USB */
PCI_INT(0x0, 0x12, 0x0, intr_data[PIRQ_EHCI1]);
PCI_INT(0x0, 0x13, 0x0, intr_data[PIRQ_EHCI2]);
PCI_INT(0x0, 0x16, 0x0, intr_data[PIRQ_EHCI3]);

/* sata */
PCI_INT(0x0, 0x11, 0x0, intr_data[PIRQ_SATA]);

/* on board NIC & Slot PCIE. */


/* PCIe Lan*/
// PCI_INT(0x0, 0x06, 0x0, 0x13); // No integrated LAN

// /* FCH PCIe PortA */
// PCI_INT(0x0, 0x15, 0x0, 0x10);
// /* FCH PCIe PortB */
// PCI_INT(0x0, 0x15, 0x1, 0x11);
// /* FCH PCIe PortC */
// PCI_INT(0x0, 0x15, 0x2, 0x12);
// /* FCH PCIe PortD */
// PCI_INT(0x0, 0x15, 0x3, 0x13);

/* GPP0 */
PCI_INT(0x0, 0x2, 0x0, 0x10); // Network 3
/* GPP1 */
PCI_INT(0x0, 0x2, 0x1, 0x11); // Network 2
/* GPP2 */
PCI_INT(0x0, 0x2, 0x2, 0x12); // Network 1
/* GPP3 */
PCI_INT(0x0, 0x2, 0x3, 0x13); // mPCI
/* GPP4 */
PCI_INT(0x0, 0x2, 0x4, 0x14); // mPCI



/*Local Ints: Type Polarity Trigger Bus ID IRQ APIC ID PIN# */
IO_LOCAL_INT(mp_ExtINT, 0, MP_APIC_ALL, 0x0);
IO_LOCAL_INT(mp_NMI, 0, MP_APIC_ALL, 0x1);
/* There is no extension information... */

/* Compute the checksums */
return mptable_finalize(mc);
}

unsigned long write_smp_table(unsigned long addr)
{
void *v;
v = smp_write_floating_table(addr, 0);
return (unsigned long)smp_write_config_table(v);
}
262 changes: 262 additions & 0 deletions src/mainboard/pcengines/apu5/romstage.c
@@ -0,0 +1,262 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2012 Advanced Micro Devices, Inc.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <stdint.h>
#include <string.h>
#include <device/pci_def.h>
#include <device/pci_ids.h>
#include <arch/acpi.h>
#include <arch/io.h>
#include <arch/stages.h>
#include <device/pnp_def.h>
#include <arch/cpu.h>
#include <cpu/x86/lapic.h>
#include <console/console.h>
#include <console/loglevel.h>
#include <cpu/amd/car.h>
#include <agesawrapper.h>
#include <northbridge/amd/pi/agesawrapper_call.h>
#include <cpu/x86/bist.h>
#include <cpu/x86/lapic.h>
#include <hudson.h>
#include <cpu/amd/pi/s3_resume.h>
#include <fchgpio.h>
#include "apu5.h"
#include <northbridge/amd/pi/00730F01/eltannorthbridge.h>
#include <eltanhudson.h>
#include <build.h>
#include "bios_knobs.h"

//
// GPIO Init Table
//
// GPIO_DEFINITION (gpio, function, outputenable, output, pullup, pulldown)
static const GPIO_CONTROL gGpioInitTable[] = {
GPIO_DEFINITION (APU5_SPD_STRAP0_GPIO, APU5_SPD_STRAP0_FUNC, 0, 0, 0, 0),
GPIO_DEFINITION (APU5_SPD_STRAP1_GPIO, APU5_SPD_STRAP1_FUNC, 0, 0, 0, 0),
GPIO_DEFINITION (APU5_SIM1RST_L_GPIO, APU5_SIM1RST_L_FUNC, 1, 1, 0, 0),
GPIO_DEFINITION (APU5_SIM2RST_L_GPIO, APU5_SIM2RST_L_FUNC, 1, 1, 0, 0),
GPIO_DEFINITION (APU5_LED1_L_GPIO, APU5_LED1_L_FUNC, 1, 0, 0, 0), // Turn on the LEDs by default
GPIO_DEFINITION (APU5_LED2_L_GPIO, APU5_LED2_L_FUNC, 1, 0, 0, 0),
GPIO_DEFINITION (APU5_LED3_L_GPIO, APU5_LED3_L_FUNC, 1, 0, 0, 0),
GPIO_DEFINITION (APU5_SIM3RST_L_GPIO, APU5_SIM3RST_L_FUNC, 1, 1, 0, 0),
GPIO_DEFINITION (APU5_SIMSWAP1_GPIO, APU5_SIMSWAP1_FUNC, 1, 1, 0, 0),
// SPKR doesn't require init, left at default
GPIO_DEFINITION (APU5_PROCHOT_GPIO, APU5_PROCHOT_FUNC, 0, 0, 0, 0),
GPIO_DEFINITION (APU5_SIMSWAP2_GPIO, APU5_SIMSWAP2_FUNC, 1, 1, 0, 0),
GPIO_DEFINITION (APU5_SIMSWAP3_GPIO, APU5_SIMSWAP3_FUNC, 1, 1, 0, 0),
{0xFF, 0xFF, 0xFF} // Terminator
};


void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx)
{
u32 val;
#if CONFIG_SVI2_SLOW_SPEED
device_t d18f3_dev = PCI_DEV(0, 0x18, 3);
#endif //CONFIG_SVI2_SLOW_SPEED
#if CONFIG_SVI_WAIT_COMP_DIS
device_t d18f5_dev = PCI_DEV(0, 0x18, 5);
#endif //CONFIG_SVI_WAIT_COMP_DIS

/*
* In Hudson RRG, PMIOxD2[5:4] is "Drive strength control for
* LpcClk[1:0]". This following register setting has been
* replicated in every reference design since Parmer, so it is
* believed to be required even though it is not documented in
* the SoC BKDGs. Without this setting, there is no serial
* output.
*/
outb(0xD2, 0xcd6);
outb(0x00, 0xcd7);

AGESAWRAPPER_PRE_CONSOLE(amdinitmmio);

if (!cpu_init_detectedx && boot_cpu()) {

u32 data, *memptr;
bool mpcie2_clk;

hudson_lpc_port80();
//
// Configure the GPIO's
//
HandleFchGpioTbl ( (GPIO_CONTROL *) &gGpioInitTable[0] );

hudson_clk_output_48Mhz();

post_code(0x31);
console_init();

printk(BIOS_INFO, "14-25-48Mhz Clock settings\n");

memptr = (u32 *)(ACPI_MMIO_BASE + MISC_BASE + FCH_MISC_REG28 );
data = *memptr;
printk(BIOS_INFO, "FCH_MISC_REG28 is 0x%08x \n", data);

memptr = (u32 *)(ACPI_MMIO_BASE + MISC_BASE + FCH_MISC_REG40 );
data = *memptr;
printk(BIOS_INFO, "FCH_MISC_REG40 is 0x%08x \n", data);

//
// Configure clock request
//
data = *((u32 *)(ACPI_MMIO_BASE + MISC_BASE+FCH_MISC_REG00));

data &= 0xFFFF0000;
data |= (0 + 1) << (0 * 4); // CLKREQ 0 to CLK0
data |= (1 + 1) << (1 * 4); // CLKREQ 1 to CLK1
// data |= (2 + 1) << (2 * 4); // do not enable CLK2, disable PE2
// make CLK3 to ignore CLKREQ# input
// force it to be always on
data |= ( 0xf ) << (3 * 4); // CLKREQ 3 to CLK3

*((u32 *)(ACPI_MMIO_BASE + MISC_BASE+FCH_MISC_REG00)) = data;

data = *((u32 *)(ACPI_MMIO_BASE + MISC_BASE+FCH_MISC_REG04));

data &= 0xFFFFFF0F;

mpcie2_clk = check_mpcie2_clk();
if (mpcie2_clk) {
// make GFXCLK to ignore CLKREQ# input
// force it to be always on
data |= 0xF << (1 * 4); // CLKREQ GFX to GFXCLK
}
else {
data |= 0xA << (1 * 4); // CLKREQ GFX to GFXCLK
}

*((u32 *)(ACPI_MMIO_BASE + MISC_BASE+FCH_MISC_REG04)) = data;

// //
// // Configure clock strength
// //
// data = *((u32 *)(ACPI_MMIO_BASE + MISC_BASE+FCH_MISC_REG24));
//
// data &= ~( (3 << 18) | (3 << 6) | (3 << 4) | (3 << 2) | (3 << 0) );
// data |= 3 << 18; // GFX CLOCK
// data |= 3 << (0 * 2); // CLK0
// data |= 3 << (1 * 2); // CLK1
// data |= 3 << (2 * 2); // CLK2
// data |= 3 << (3 * 2); // CLK3
//
// *((u32 *)(ACPI_MMIO_BASE + MISC_BASE+FCH_MISC_REG24)) = data;
}

/* Halt if there was a built in self test failure */
post_code(0x34);
report_bist_failure(bist);

/* Load MPB */
val = cpuid_eax(1);
printk(BIOS_DEBUG, "BSP Family_Model: %08x \n", val);
printk(BIOS_DEBUG, "cpu_init_detectedx = %08lx \n", cpu_init_detectedx);

/*
* This refers to LpcClkDrvSth settling time. Without this setting, processor
* initialization is slow or incorrect, so this wait has been replicated from
* earlier development boards.
*/
{ int i; for(i = 0; i < 200000; i++) inb(0xCD6); }

post_code(0x37);
AGESAWRAPPER(amdinitreset);

/* TODO There is no debug output between the return from amdinitreset and amdinitearly */

post_code(0x38);
printk(BIOS_DEBUG, "Got past avalon_early_setup\n");

post_code(0x39);
AGESAWRAPPER(amdinitearly);

/*
// Moved here to prevent double signon message
// amdinitreset AGESA code might issue a reset when the hardware is in a wrong state.
*/

printk(BIOS_ERR, CONFIG_MAINBOARD_PART_NUMBER "\n");
printk(BIOS_ERR, "coreboot build " COREBOOT_YYYYMMDD_DATE "\n");

#if CONFIG_SVI2_SLOW_SPEED
/* Force SVI2 to slow speed for APU5 */
val = pci_read_config32( d18f3_dev, 0xA0);
if ( val & (1 << 14 ) ) {

printk(BIOS_DEBUG, "SVI2 FREQUENCY 20 Mhz changing to 3.4\n");
val &= ~(1 << 14 );
pci_write_config32(d18f3_dev, 0xA0, val );

} else {

printk(BIOS_DEBUG, "SVI2 FREQUENCY 3.4 Mhz\n");
}
#endif //CONFIG_SVI2_SLOW_SPEED

#if CONFIG_SVI_WAIT_COMP_DIS
/* Disable SVI2 controller to wait for command completion */
val = pci_read_config32( d18f5_dev, 0x12C);
if ( val & (1 << 30 ) ) {

printk(BIOS_DEBUG, "SVI2 Wait completion disabled\n");

} else {

printk(BIOS_DEBUG, "Disabling SVI2 Wait completion\n");
val |= (1 << 30 );
pci_write_config32(d18f5_dev, 0x12C, val );
}

#endif //CONFIG_SVI_WAIT_COMP_DIS

int s3resume = acpi_is_wakeup_s3();
if (!s3resume) {
post_code(0x40);
AGESAWRAPPER(amdinitpost);

//PspMboxBiosCmdDramInfo();
post_code(0x41);
AGESAWRAPPER(amdinitenv);
/*
If code hangs here, please check cahaltasm.S
*/
disable_cache_as_ram();

} else { /* S3 detect */

printk(BIOS_INFO, "S3 detected\n");

post_code(0x60);
AGESAWRAPPER(amdinitresume);

AGESAWRAPPER(amds3laterestore);

post_code(0x61);
prepare_for_resume();
}

outb(0xEA, 0xCD6);
outb(0x1, 0xcd7);

post_code(0x50);
copy_and_run();

post_code(0x54); /* Should never see this post code. */
}