AMD Kabini: Add northbridge AGESA wrapper (new AMD processor)

src/arch/x86/boot/tables.c and src/include/device/pci_ids.h are also
changed because these two files depend on F16kb northbridge macros

Change-Id: Iedc842f0b230826675703fc78ed8001a978319c5
Reviewed-by: Marc Jones <marc.jones@se-eng.com>
Signed-off-by: Bruce Griffith <Bruce.Griffith@se-eng.com>
Reviewed-by: Bruce Griffith <bruce.griffith@se-eng.com>
Tested-by: Bruce Griffith <bruce.griffith@se-eng.com>
Reviewed-on: http://review.coreboot.org/3782
Tested-by: build bot (Jenkins)
Reviewed-by: Martin Roth <martin.roth@se-eng.com>
This commit is contained in:
Siyuan Wang 2013-07-09 17:16:20 +08:00 committed by Bruce Griffith
parent 5d7d09c4ab
commit 3e32cc00d1
14 changed files with 2257 additions and 1 deletions

View File

@ -214,7 +214,7 @@ struct lb_memory *write_tables(void)
*/
cbmem_add(CBMEM_ID_RESUME, HIGH_MEMORY_SAVE);
#endif
#if CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY14 || CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY15_TN
#if CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY14 || CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY15_TN || CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY16_KB
cbmem_add(CBMEM_ID_RESUME_SCRATCH, CONFIG_HIGH_SCRATCH_MEMORY_SIZE);
#endif
#endif

View File

@ -286,6 +286,7 @@
#define PCI_DEVICE_ID_AMD_15H_MODEL_000F_NB_HT 0x1600
#define PCI_DEVICE_ID_AMD_15H_MODEL_001F_NB_HT 0x1400
#define PCI_DEVICE_ID_AMD_16H_MODEL_000F_NB_HT 0x1536
#define PCI_DEVICE_ID_AMD_10H_NB_HT 0x1200
#define PCI_DEVICE_ID_AMD_15H_NB_IOMMU 0x1419

View File

@ -36,5 +36,6 @@ source src/northbridge/amd/agesa/family12/Kconfig
source src/northbridge/amd/agesa/family14/Kconfig
source src/northbridge/amd/agesa/family15/Kconfig
source src/northbridge/amd/agesa/family15tn/Kconfig
source src/northbridge/amd/agesa/family16kb/Kconfig
endif # NORTHBRIDGE_AMD_AGESA

View File

@ -21,3 +21,4 @@ subdirs-$(CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY12) += family12
subdirs-$(CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY14) += family14
subdirs-$(CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY15) += family15
subdirs-$(CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY15_TN) += family15tn
subdirs-$(CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY16_KB) += family16kb

View File

@ -0,0 +1,41 @@
##
## This file is part of the coreboot project.
##
## Copyright (C) 2007-2009 coresystems GmbH
##
## 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
##
config NORTHBRIDGE_AMD_AGESA_FAMILY16_KB
bool
select MMCONF_SUPPORT
if NORTHBRIDGE_AMD_AGESA_FAMILY16_KB
config HW_MEM_HOLE_SIZEK
hex
default 0x100000
config HW_MEM_HOLE_SIZE_AUTO_INC
bool
default n
config MMCONF_BASE_ADDRESS
hex
default 0xA0000000
config MMCONF_BUS_NUMBER
int
default 256
endif

View File

@ -0,0 +1,25 @@
#
# 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
#
romstage-y += fam16kb_callouts.c
romstage-y += dimmSpd.c
ramstage-y += northbridge.c
ramstage-y += fam16kb_callouts.c
ramstage-y += dimmSpd.c

View File

@ -0,0 +1,302 @@
/*
* 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
*/
/*
* No includes in this file because it is included into northbridge.c.
*/
struct dram_base_mask_t {
u32 base; //[47:27] at [28:8]
u32 mask; //[47:27] at [28:8] and enable at bit 0
};
static struct dram_base_mask_t get_dram_base_mask(u32 nodeid)
{
device_t dev;
struct dram_base_mask_t d;
#if defined(__PRE_RAM__)
dev = PCI_DEV(CONFIG_CBB, CONFIG_CDB, 1);
#else
dev = __f1_dev[0];
#endif // defined(__PRE_RAM__)
u32 temp;
temp = pci_read_config32(dev, 0x44); //[39:24] at [31:16]
d.mask = (temp & 0xffff0000); // mask out DramMask [26:24] too
temp = pci_read_config32(dev, 0x40); //[35:24] at [27:16]
d.mask |= (temp & 1); // read enable bit
d.base = (temp & 0x0fff0000); // mask out DramBase [26:24) too
return d;
}
#if CONFIG_EXT_CONF_SUPPORT
static void set_addr_map_reg_4_6_in_one_node(u32 nodeid, u32 cfg_map_dest,
u32 busn_min, u32 busn_max,
u32 type)
{
device_t dev;
u32 i;
u32 tempreg;
u32 index_min, index_max;
u32 dest_min, dest_max;
index_min = busn_min>>2; dest_min = busn_min - (index_min<<2);
index_max = busn_max>>2; dest_max = busn_max - (index_max<<2);
// three case: index_min==index_max, index_min+1=index_max; index_min+1<index_max
#if defined(__PRE_RAM__)
dev = NODE_PCI(nodeid, 1);
#else
dev = __f1_dev[nodeid];
#endif // defined(__PRE_RAM__)
if(index_min== index_max) {
pci_write_config32(dev, 0x110, index_min | (type<<28));
tempreg = pci_read_config32(dev, 0x114);
for(i=dest_min; i<=dest_max; i++) {
tempreg &= ~(0xff<<(i*8));
tempreg |= (cfg_map_dest<<(i*8));
}
pci_write_config32(dev, 0x110, index_min | (type<<28)); // do i need to write it again
pci_write_config32(dev, 0x114, tempreg);
} else if(index_min<index_max) {
pci_write_config32(dev, 0x110, index_min | (type<<28));
tempreg = pci_read_config32(dev, 0x114);
for(i=dest_min; i<=3; i++) {
tempreg &= ~(0xff<<(i*8));
tempreg |= (cfg_map_dest<<(i*8));
}
pci_write_config32(dev, 0x110, index_min | (type<<28)); // do i need to write it again
pci_write_config32(dev, 0x114, tempreg);
pci_write_config32(dev, 0x110, index_max | (type<<28));
tempreg = pci_read_config32(dev, 0x114);
for(i=0; i<=dest_max; i++) {
tempreg &= ~(0xff<<(i*8));
tempreg |= (cfg_map_dest<<(i*8));
}
pci_write_config32(dev, 0x110, index_max | (type<<28)); // do i need to write it again
pci_write_config32(dev, 0x114, tempreg);
if((index_max-index_min)>1) {
tempreg = 0;
for(i=0; i<=3; i++) {
tempreg &= ~(0xff<<(i*8));
tempreg |= (cfg_map_dest<<(i*8));
}
for(i=index_min+1; i<index_max;i++) {
pci_write_config32(dev, 0x110, i | (type<<28));
pci_write_config32(dev, 0x114, tempreg);
}
}
}
}
#endif // CONFIG_EXT_CONF_SUPPORT
#if defined(__PRE_RAM__)
static void set_ht_c_io_addr_reg(u32 nodeid, u32 linkn, u32 ht_c_index,
u32 io_min, u32 io_max, u32 nodes)
{
u32 i;
u32 tempreg;
device_t dev;
#if CONFIG_EXT_CONF_SUPPORT
if(ht_c_index<4) {
#endif
/* io range allocation */
tempreg = (nodeid&0xf) | ((nodeid & 0x30)<<(8-4)) | (linkn<<4) | ((io_max&0xf0)<<(12-4)); //limit
for(i=0; i<nodes; i++) {
dev = NODE_PCI(i, 1);
pci_write_config32(dev, 0xC4 + ht_c_index * 8, tempreg);
}
tempreg = 3 /*| ( 3<<4)*/ | ((io_min&0xf0)<<(12-4)); //base :ISA and VGA ?
for(i=0; i<nodes; i++){
dev = NODE_PCI(i, 1);
pci_write_config32(dev, 0xC0 + ht_c_index * 8, tempreg);
}
#if CONFIG_EXT_CONF_SUPPORT
return;
}
u32 cfg_map_dest;
u32 j;
// if ht_c_index > 3, We should use extend space
if(io_min>io_max) return;
// for nodeid at first
cfg_map_dest = (1<<7) | (1<<6) | (linkn<<0);
set_addr_map_reg_4_6_in_one_node(nodeid, cfg_map_dest, io_min, io_max, 4);
// all other nodes
cfg_map_dest = (1<<7) | (0<<6) | (nodeid<<0);
for(j = 0; j< nodes; j++) {
if(j== nodeid) continue;
set_addr_map_reg_4_6_in_one_node(j,cfg_map_dest, io_min, io_max, 4);
}
#endif // CONFIG_EXT_CONF_SUPPORT
}
static void clear_ht_c_io_addr_reg(u32 nodeid, u32 linkn, u32 ht_c_index,
u32 io_min, u32 io_max, u32 nodes)
{
u32 i;
device_t dev;
#if CONFIG_EXT_CONF_SUPPORT
if(ht_c_index<4) {
#endif
/* io range allocation */
for(i=0; i<nodes; i++) {
dev = NODE_PCI(i, 1);
pci_write_config32(dev, 0xC4 + ht_c_index * 8, 0);
pci_write_config32(dev, 0xC0 + ht_c_index * 8, 0);
}
#if CONFIG_EXT_CONF_SUPPORT
return;
}
// : if hc_c_index > 3, We should use io_min, io_max to clear extend space
u32 cfg_map_dest;
u32 j;
// all nodes
cfg_map_dest = 0;
for(j = 0; j< nodes; j++) {
set_addr_map_reg_4_6_in_one_node(j,cfg_map_dest, io_min, io_max, 4);
}
#endif
}
#endif // defined(__PRE_RAM__)
#if !defined(__PRE_RAM__)
static u32 get_io_addr_index(u32 nodeid, u32 linkn)
{
#if 0
u32 index;
for(index=0; index<256; index++) {
if((sysconf.conf_io_addrx[index+4] == 0)){
sysconf.conf_io_addr[index+4] = (nodeid & 0x3f) ;
sysconf.conf_io_addrx[index+4] = 1 | ((linkn & 0x7)<<4);
return index;
}
}
#endif
return 0;
}
static u32 get_mmio_addr_index(u32 nodeid, u32 linkn)
{
#if 0
u32 index;
for(index=0; index<64; index++) {
if((sysconf.conf_mmio_addrx[index+8] == 0)){
sysconf.conf_mmio_addr[index+8] = (nodeid & 0x3f) ;
sysconf.conf_mmio_addrx[index+8] = 1 | ((linkn & 0x7)<<4);
return index;
}
}
#endif
return 0;
}
static void set_io_addr_reg(device_t dev, u32 nodeid, u32 linkn, u32 reg,
u32 io_min, u32 io_max)
{
u32 tempreg;
#if CONFIG_EXT_CONF_SUPPORT
if(reg!=0x110) {
#endif
/* io range allocation */
tempreg = (nodeid&0xf) | ((nodeid & 0x30)<<(8-4)) | (linkn<<4) | ((io_max&0xf0)<<(12-4)); //limit
pci_write_config32(__f1_dev[0], reg+4, tempreg);
tempreg = 3 /*| ( 3<<4)*/ | ((io_min&0xf0)<<(12-4)); //base :ISA and VGA ?
#if 0
// FIXME: can we use VGA reg instead?
if (dev->link[link].bridge_ctrl & PCI_BRIDGE_CTL_VGA) {
printk(BIOS_SPEW, "%s, enabling legacy VGA IO forwarding for %s link %s\n",
__func__, dev_path(dev), link);
tempreg |= PCI_IO_BASE_VGA_EN;
}
if (dev->link[link].bridge_ctrl & PCI_BRIDGE_CTL_NO_ISA) {
tempreg |= PCI_IO_BASE_NO_ISA;
}
#endif
pci_write_config32(__f1_dev[0], reg, tempreg);
#if CONFIG_EXT_CONF_SUPPORT
return;
}
u32 cfg_map_dest;
u32 j;
// if ht_c_index > 3, We should use extend space
if(io_min>io_max) return;
// for nodeid at first
cfg_map_dest = (1<<7) | (1<<6) | (linkn<<0);
set_addr_map_reg_4_6_in_one_node(nodeid, cfg_map_dest, io_min, io_max, 4);
#endif // CONFIG_EXT_CONF_SUPPORT
}
static void set_mmio_addr_reg(u32 nodeid, u32 linkn, u32 reg, u32 index, u32 mmio_min, u32 mmio_max, u32 nodes)
{
u32 tempreg;
#if CONFIG_EXT_CONF_SUPPORT
if(reg!=0x110) {
#endif
/* io range allocation */
tempreg = (nodeid&0xf) | (linkn<<4) | (mmio_max&0xffffff00); //limit
pci_write_config32(__f1_dev[0], reg+4, tempreg);
tempreg = 3 | (nodeid & 0x30) | (mmio_min&0xffffff00);
pci_write_config32(__f1_dev[0], reg, tempreg);
#if CONFIG_EXT_CONF_SUPPORT
return;
}
device_t dev;
u32 j;
// if ht_c_index > 3, We should use extend space
// for nodeid at first
u32 enable;
if(mmio_min>mmio_max) {
return;
}
enable = 1;
dev = __f1_dev[nodeid];
tempreg = ((mmio_min>>3) & 0x1fffff00)| (1<<6) | (linkn<<0);
pci_write_config32(dev, 0x110, index | (2<<28));
pci_write_config32(dev, 0x114, tempreg);
tempreg = ((mmio_max>>3) & 0x1fffff00) | enable;
pci_write_config32(dev, 0x110, index | (3<<28));
pci_write_config32(dev, 0x114, tempreg);
#endif // CONFIG_EXT_CONF_SUPPORT
}
#endif // !defined(__PRE_RAM__)

View File

@ -0,0 +1,28 @@
/*
* This file is part of the coreboot project.
*
* 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
*/
#ifndef _AGESA_FAM16KB_CHIP_H_
#define _AGESA_FAM16KB_CHIP_H_
struct northbridge_amd_agesa_family16kb_config
{
u8 spdAddrLookup[2][2][4];
};
#endif

View File

@ -0,0 +1,160 @@
/*
* 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 <device/pci_def.h>
#include <device/device.h>
/* warning: Porting.h includes an open #pragma pack(1) */
#include "Porting.h"
#include "AGESA.h"
#include "amdlib.h"
#include "dimmSpd.h"
#include "chip.h"
#define DIMENSION(array)(sizeof (array)/ sizeof (array [0]))
/*-----------------------------------------------------------------------------
*
* readSmbusByteData - read a single SPD byte from any offset
*/
static int readSmbusByteData (int iobase, int address, char *buffer, int offset)
{
unsigned int status;
UINT64 limit;
address |= 1; // set read bit
__outbyte (iobase + 0, 0xFF); // clear error status
__outbyte (iobase + 1, 0x1F); // clear error status
__outbyte (iobase + 3, offset); // offset in eeprom
__outbyte (iobase + 4, address); // slave address and read bit
__outbyte (iobase + 2, 0x48); // read byte command
// time limit to avoid hanging for unexpected error status (should never happen)
limit = __rdtsc () + 2000000000 / 10;
for (;;)
{
status = __inbyte (iobase);
if (__rdtsc () > limit) break;
if ((status & 2) == 0) continue; // SMBusInterrupt not set, keep waiting
if ((status & 1) == 1) continue; // HostBusy set, keep waiting
break;
}
buffer [0] = __inbyte (iobase + 5);
if (status == 2) status = 0; // check for done with no errors
return status;
}
/*-----------------------------------------------------------------------------
*
* readSmbusByte - read a single SPD byte from the default offset
* this function is faster function readSmbusByteData
*/
static int readSmbusByte (int iobase, int address, char *buffer)
{
unsigned int status;
UINT64 limit;
__outbyte (iobase + 0, 0xFF); // clear error status
__outbyte (iobase + 2, 0x44); // read command
// time limit to avoid hanging for unexpected error status
limit = __rdtsc () + 2000000000 / 10;
for (;;)
{
status = __inbyte (iobase);
if (__rdtsc () > limit) break;
if ((status & 2) == 0) continue; // SMBusInterrupt not set, keep waiting
if ((status & 1) == 1) continue; // HostBusy set, keep waiting
break;
}
buffer [0] = __inbyte (iobase + 5);
if (status == 2) status = 0; // check for done with no errors
return status;
}
/*---------------------------------------------------------------------------
*
* readspd - Read one or more SPD bytes from a DIMM.
* Start with offset zero and read sequentially.
* Optimization relies on autoincrement to avoid
* sending offset for every byte.
* Reads 128 bytes in 7-8 ms at 400 KHz.
*/
static int readspd (int iobase, int SmbusSlaveAddress, char *buffer, int count)
{
int index, error;
/* read the first byte using offset zero */
error = readSmbusByteData (iobase, SmbusSlaveAddress, buffer, 0);
if (error) return error;
/* read the remaining bytes using auto-increment for speed */
for (index = 1; index < count; index++)
{
error = readSmbusByte (iobase, SmbusSlaveAddress, &buffer [index]);
if (error) return error;
}
return 0;
}
static void writePmReg (int reg, int data)
{
__outbyte (0xCD6, reg);
__outbyte (0xCD7, data);
}
static void setupFch (int ioBase)
{
writePmReg (0x2D, ioBase >> 8);
writePmReg (0x2C, ioBase | 1);
__outbyte (ioBase + 0x0E, 66000000 / 400000 / 4); // set SMBus clock to 400 KHz
}
AGESA_STATUS AmdMemoryReadSPD (UINT32 unused1, UINT32 unused2, AGESA_READ_SPD_PARAMS *info)
{
int spdAddress, ioBase;
ROMSTAGE_CONST struct device *dev = dev_find_slot(0, PCI_DEVFN(0x18, 2));
ROMSTAGE_CONST struct northbridge_amd_agesa_family16kb_config *config = dev->chip_info;
if ((dev == 0) || (config == 0))
return AGESA_ERROR;
if (info->SocketId >= DIMENSION(config->spdAddrLookup ))
return AGESA_ERROR;
if (info->MemChannelId >= DIMENSION(config->spdAddrLookup[0] ))
return AGESA_ERROR;
if (info->DimmId >= DIMENSION(config->spdAddrLookup[0][0]))
return AGESA_ERROR;
spdAddress = config->spdAddrLookup
[info->SocketId] [info->MemChannelId] [info->DimmId];
if (spdAddress == 0) return AGESA_ERROR;
ioBase = 0xB00;
setupFch (ioBase);
return readspd (ioBase, spdAddress, (void *) info->Buffer, 128);
}

View File

@ -0,0 +1,56 @@
/*
* 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
*/
/*----------------------------------------------------------------------------------------
* M O D U L E S U S E D
*----------------------------------------------------------------------------------------
*/
#ifndef _DIMMSPD_H_
#define _DIMMSPD_H_
/*----------------------------------------------------------------------------------------
* D E F I N I T I O N S A N D M A C R O S
*----------------------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------------------
* T Y P E D E F S A N D S T R U C T U R E S
*----------------------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------------------
* P R O T O T Y P E S O F L O C A L F U N C T I O N S
*----------------------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------------------
* E X P O R T E D F U N C T I O N S
*----------------------------------------------------------------------------------------
*/
AGESA_STATUS
AmdMemoryReadSPD (IN UINT32 Func, IN UINT32 Data, IN OUT AGESA_READ_SPD_PARAMS *SpdData);
/*---------------------------------------------------------------------------------------
* L O C A L F U N C T I O N S
*---------------------------------------------------------------------------------------
*/
#endif

View File

@ -0,0 +1,415 @@
/*
* 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 "agesawrapper.h"
#include "amdlib.h"
#include "Ids.h"
#include "OptionsIds.h"
#include "heapManager.h"
#include "FchPlatform.h"
#include "cbfs.h"
#include "dimmSpd.h"
#include "fam16kb_callouts.h"
AGESA_STATUS fam16kb_AllocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
{
UINT32 AvailableHeapSize;
UINT8 *BiosHeapBaseAddr;
UINT32 CurrNodeOffset;
UINT32 PrevNodeOffset;
UINT32 FreedNodeOffset;
UINT32 BestFitNodeOffset;
UINT32 BestFitPrevNodeOffset;
UINT32 NextFreeOffset;
BIOS_BUFFER_NODE *CurrNodePtr;
BIOS_BUFFER_NODE *FreedNodePtr;
BIOS_BUFFER_NODE *BestFitNodePtr;
BIOS_BUFFER_NODE *BestFitPrevNodePtr;
BIOS_BUFFER_NODE *NextFreePtr;
BIOS_HEAP_MANAGER *BiosHeapBasePtr;
AGESA_BUFFER_PARAMS *AllocParams;
AllocParams = ((AGESA_BUFFER_PARAMS *) ConfigPtr);
AllocParams->BufferPointer = NULL;
AvailableHeapSize = BIOS_HEAP_SIZE - sizeof (BIOS_HEAP_MANAGER);
BiosHeapBaseAddr = (UINT8 *) GetHeapBase(&(AllocParams->StdHeader));
BiosHeapBasePtr = (BIOS_HEAP_MANAGER *) BiosHeapBaseAddr;
if (BiosHeapBasePtr->StartOfAllocatedNodes == 0) {
/* First allocation */
CurrNodeOffset = sizeof (BIOS_HEAP_MANAGER);
CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset);
CurrNodePtr->BufferHandle = AllocParams->BufferHandle;
CurrNodePtr->BufferSize = AllocParams->BufferLength;
CurrNodePtr->NextNodeOffset = 0;
AllocParams->BufferPointer = (UINT8 *) CurrNodePtr + sizeof (BIOS_BUFFER_NODE);
/* Update the remaining free space */
FreedNodeOffset = CurrNodeOffset + CurrNodePtr->BufferSize + sizeof (BIOS_BUFFER_NODE);
FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset);
FreedNodePtr->BufferSize = AvailableHeapSize - sizeof (BIOS_BUFFER_NODE) - CurrNodePtr->BufferSize;
FreedNodePtr->NextNodeOffset = 0;
/* Update the offsets for Allocated and Freed nodes */
BiosHeapBasePtr->StartOfAllocatedNodes = CurrNodeOffset;
BiosHeapBasePtr->StartOfFreedNodes = FreedNodeOffset;
} else {
/* Find out whether BufferHandle has been allocated on the heap. */
/* If it has, return AGESA_BOUNDS_CHK */
CurrNodeOffset = BiosHeapBasePtr->StartOfAllocatedNodes;
CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset);
while (CurrNodeOffset != 0) {
CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset);
if (CurrNodePtr->BufferHandle == AllocParams->BufferHandle) {
return AGESA_BOUNDS_CHK;
}
CurrNodeOffset = CurrNodePtr->NextNodeOffset;
/* If BufferHandle has not been allocated on the heap, CurrNodePtr here points
to the end of the allocated nodes list.
*/
}
/* Find the node that best fits the requested buffer size */
FreedNodeOffset = BiosHeapBasePtr->StartOfFreedNodes;
PrevNodeOffset = FreedNodeOffset;
BestFitNodeOffset = 0;
BestFitPrevNodeOffset = 0;
while (FreedNodeOffset != 0) {
FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset);
if (FreedNodePtr->BufferSize >= (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE))) {
if (BestFitNodeOffset == 0) {
/* First node that fits the requested buffer size */
BestFitNodeOffset = FreedNodeOffset;
BestFitPrevNodeOffset = PrevNodeOffset;
} else {
/* Find out whether current node is a better fit than the previous nodes */
BestFitNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitNodeOffset);
if (BestFitNodePtr->BufferSize > FreedNodePtr->BufferSize) {
BestFitNodeOffset = FreedNodeOffset;
BestFitPrevNodeOffset = PrevNodeOffset;
}
}
}
PrevNodeOffset = FreedNodeOffset;
FreedNodeOffset = FreedNodePtr->NextNodeOffset;
} /* end of while loop */
if (BestFitNodeOffset == 0) {
/* If we could not find a node that fits the requested buffer */
/* size, return AGESA_BOUNDS_CHK */
return AGESA_BOUNDS_CHK;
} else {
BestFitNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitNodeOffset);
BestFitPrevNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitPrevNodeOffset);
/* If BestFitNode is larger than the requested buffer, fragment the node further */
if (BestFitNodePtr->BufferSize > (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE))) {
NextFreeOffset = BestFitNodeOffset + AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE);
NextFreePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + NextFreeOffset);
NextFreePtr->BufferSize = BestFitNodePtr->BufferSize - (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE));
NextFreePtr->NextNodeOffset = BestFitNodePtr->NextNodeOffset;
} else {
/* Otherwise, next free node is NextNodeOffset of BestFitNode */
NextFreeOffset = BestFitNodePtr->NextNodeOffset;
}
/* If BestFitNode is the first buffer in the list, then update
StartOfFreedNodes to reflect the new free node
*/
if (BestFitNodeOffset == BiosHeapBasePtr->StartOfFreedNodes) {
BiosHeapBasePtr->StartOfFreedNodes = NextFreeOffset;
} else {
BestFitPrevNodePtr->NextNodeOffset = NextFreeOffset;
}
/* Add BestFitNode to the list of Allocated nodes */
CurrNodePtr->NextNodeOffset = BestFitNodeOffset;
BestFitNodePtr->BufferSize = AllocParams->BufferLength;
BestFitNodePtr->BufferHandle = AllocParams->BufferHandle;
BestFitNodePtr->NextNodeOffset = 0;
/* Remove BestFitNode from list of Freed nodes */
AllocParams->BufferPointer = (UINT8 *) BestFitNodePtr + sizeof (BIOS_BUFFER_NODE);
}
}
return AGESA_SUCCESS;
}
AGESA_STATUS fam16kb_DeallocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
{
UINT8 *BiosHeapBaseAddr;
UINT32 AllocNodeOffset;
UINT32 PrevNodeOffset;
UINT32 NextNodeOffset;
UINT32 FreedNodeOffset;
UINT32 EndNodeOffset;
BIOS_BUFFER_NODE *AllocNodePtr;
BIOS_BUFFER_NODE *PrevNodePtr;
BIOS_BUFFER_NODE *FreedNodePtr;
BIOS_BUFFER_NODE *NextNodePtr;
BIOS_HEAP_MANAGER *BiosHeapBasePtr;
AGESA_BUFFER_PARAMS *AllocParams;
AllocParams = (AGESA_BUFFER_PARAMS *) ConfigPtr;
BiosHeapBaseAddr = (UINT8 *) GetHeapBase(&(AllocParams->StdHeader));
BiosHeapBasePtr = (BIOS_HEAP_MANAGER *) BiosHeapBaseAddr;
/* Find target node to deallocate in list of allocated nodes.
Return AGESA_BOUNDS_CHK if the BufferHandle is not found
*/
AllocNodeOffset = BiosHeapBasePtr->StartOfAllocatedNodes;
AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
PrevNodeOffset = AllocNodeOffset;
while (AllocNodePtr->BufferHandle != AllocParams->BufferHandle) {
if (AllocNodePtr->NextNodeOffset == 0) {
return AGESA_BOUNDS_CHK;
}
PrevNodeOffset = AllocNodeOffset;
AllocNodeOffset = AllocNodePtr->NextNodeOffset;
AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
}
/* Remove target node from list of allocated nodes */
PrevNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + PrevNodeOffset);
PrevNodePtr->NextNodeOffset = AllocNodePtr->NextNodeOffset;
/* Zero out the buffer, and clear the BufferHandle */
LibAmdMemFill ((UINT8 *)AllocNodePtr + sizeof (BIOS_BUFFER_NODE), 0, AllocNodePtr->BufferSize, &(AllocParams->StdHeader));
AllocNodePtr->BufferHandle = 0;
AllocNodePtr->BufferSize += sizeof (BIOS_BUFFER_NODE);
/* Add deallocated node in order to the list of freed nodes */
FreedNodeOffset = BiosHeapBasePtr->StartOfFreedNodes;
FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset);
EndNodeOffset = AllocNodeOffset + AllocNodePtr->BufferSize;
if (AllocNodeOffset < FreedNodeOffset) {
/* Add to the start of the freed list */
if (EndNodeOffset == FreedNodeOffset) {
/* If the freed node is adjacent to the first node in the list, concatenate both nodes */
AllocNodePtr->BufferSize += FreedNodePtr->BufferSize;
AllocNodePtr->NextNodeOffset = FreedNodePtr->NextNodeOffset;
/* Clear the BufferSize and NextNodeOffset of the previous first node */
FreedNodePtr->BufferSize = 0;
FreedNodePtr->NextNodeOffset = 0;
} else {
/* Otherwise, add freed node to the start of the list
Update NextNodeOffset and BufferSize to include the
size of BIOS_BUFFER_NODE
*/
AllocNodePtr->NextNodeOffset = FreedNodeOffset;
}
/* Update StartOfFreedNodes to the new first node */
BiosHeapBasePtr->StartOfFreedNodes = AllocNodeOffset;
} else {
/* Traverse list of freed nodes to find where the deallocated node
should be place
*/
NextNodeOffset = FreedNodeOffset;
NextNodePtr = FreedNodePtr;
while (AllocNodeOffset > NextNodeOffset) {
PrevNodeOffset = NextNodeOffset;
if (NextNodePtr->NextNodeOffset == 0) {
break;
}
NextNodeOffset = NextNodePtr->NextNodeOffset;
NextNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + NextNodeOffset);
}
/* If deallocated node is adjacent to the next node,
concatenate both nodes
*/
if (NextNodeOffset == EndNodeOffset) {
NextNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + NextNodeOffset);
AllocNodePtr->BufferSize += NextNodePtr->BufferSize;
AllocNodePtr->NextNodeOffset = NextNodePtr->NextNodeOffset;
NextNodePtr->BufferSize = 0;
NextNodePtr->NextNodeOffset = 0;
} else {
/*AllocNodePtr->NextNodeOffset = FreedNodePtr->NextNodeOffset; */
AllocNodePtr->NextNodeOffset = NextNodeOffset;
}
/* If deallocated node is adjacent to the previous node,
concatenate both nodes
*/
PrevNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + PrevNodeOffset);
EndNodeOffset = PrevNodeOffset + PrevNodePtr->BufferSize;
if (AllocNodeOffset == EndNodeOffset) {
PrevNodePtr->NextNodeOffset = AllocNodePtr->NextNodeOffset;
PrevNodePtr->BufferSize += AllocNodePtr->BufferSize;
AllocNodePtr->BufferSize = 0;
AllocNodePtr->NextNodeOffset = 0;
} else {
PrevNodePtr->NextNodeOffset = AllocNodeOffset;
}
}
return AGESA_SUCCESS;
}
AGESA_STATUS fam16kb_LocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
{
UINT32 AllocNodeOffset;
UINT8 *BiosHeapBaseAddr;
BIOS_BUFFER_NODE *AllocNodePtr;
BIOS_HEAP_MANAGER *BiosHeapBasePtr;
AGESA_BUFFER_PARAMS *AllocParams;
AllocParams = (AGESA_BUFFER_PARAMS *) ConfigPtr;
BiosHeapBaseAddr = (UINT8 *) GetHeapBase(&(AllocParams->StdHeader));
BiosHeapBasePtr = (BIOS_HEAP_MANAGER *) BiosHeapBaseAddr;
AllocNodeOffset = BiosHeapBasePtr->StartOfAllocatedNodes;
AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
while (AllocParams->BufferHandle != AllocNodePtr->BufferHandle) {
if (AllocNodePtr->NextNodeOffset == 0) {
AllocParams->BufferPointer = NULL;
AllocParams->BufferLength = 0;
return AGESA_BOUNDS_CHK;
} else {
AllocNodeOffset = AllocNodePtr->NextNodeOffset;
AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
}
}
AllocParams->BufferPointer = (UINT8 *) ((UINT8 *) AllocNodePtr + sizeof (BIOS_BUFFER_NODE));
AllocParams->BufferLength = AllocNodePtr->BufferSize;
return AGESA_SUCCESS;
}
CONST IDS_NV_ITEM IdsData[] =
{
{
0xFFFF,
0xFFFF
}
};
#define NUM_IDS_ENTRIES (sizeof (IdsData) / sizeof (IDS_NV_ITEM))
AGESA_STATUS fam16kb_GetIdsInitData (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
{
UINTN i;
IDS_NV_ITEM *IdsPtr;
IdsPtr = ((IDS_CALLOUT_STRUCT *) ConfigPtr)->IdsNvPtr;
if (Data == IDS_CALLOUT_INIT) {
for (i = 0; i < NUM_IDS_ENTRIES; i++) {
IdsPtr[i].IdsNvValue = IdsData[i].IdsNvValue;
IdsPtr[i].IdsNvId = IdsData[i].IdsNvId;
}
}
return AGESA_SUCCESS;
}
AGESA_STATUS fam16kb_Reset (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
{
AGESA_STATUS Status;
UINT8 Value;
UINTN ResetType;
AMD_CONFIG_PARAMS *StdHeader;
ResetType = Data;
StdHeader = ConfigPtr;
//
// Perform the RESET based upon the ResetType. In case of
// WARM_RESET_WHENVER and COLD_RESET_WHENEVER, the request will go to
// AmdResetManager. During the critical condition, where reset is required
// immediately, the reset will be invoked directly by writing 0x04 to port
// 0xCF9 (Reset Port).
//
switch (ResetType) {
case WARM_RESET_WHENEVER:
case COLD_RESET_WHENEVER:
break;
case WARM_RESET_IMMEDIATELY:
case COLD_RESET_IMMEDIATELY:
Value = 0x06;
LibAmdIoWrite (AccessWidth8, 0xCf9, &Value, StdHeader);
break;
default:
break;
}
Status = 0;
return Status;
}
AGESA_STATUS fam16kb_RunFuncOnAp (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
{
AGESA_STATUS Status;
Status = agesawrapper_amdlaterunaptask (Func, Data, ConfigPtr);
return Status;
}
/* Call the host environment interface to provide a user hook opportunity. */
AGESA_STATUS fam16kb_HookBeforeDQSTraining (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
{
return AGESA_SUCCESS;
}
/* Call the host environment interface to provide a user hook opportunity. */
AGESA_STATUS fam16kb_HookBeforeExitSelfRefresh (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
{
return AGESA_SUCCESS;
}
AGESA_STATUS fam16kb_DefaultRet (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
{
return AGESA_UNSUPPORTED;
}
AGESA_STATUS fam16kb_HookGfxGetVbiosImage(UINT32 Func, UINT32 FchData, VOID *ConfigPrt)
{
GFX_VBIOS_IMAGE_INFO *pVbiosImageInfo = (GFX_VBIOS_IMAGE_INFO *)ConfigPrt;
pVbiosImageInfo->ImagePtr = cbfs_get_file_content(
CBFS_DEFAULT_MEDIA, "pci"CONFIG_VGA_BIOS_ID".rom",
CBFS_TYPE_OPTIONROM);
/* printk(BIOS_DEBUG, "IMGptr=%x\n", pVbiosImageInfo->ImagePtr); */
return pVbiosImageInfo->ImagePtr == NULL ? AGESA_WARNING : AGESA_SUCCESS;
}
AGESA_STATUS fam16kb_ReadSpd (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
{
AGESA_STATUS Status;
Status = AmdMemoryReadSPD (Func, Data, ConfigPtr);
return Status;
}

View File

@ -0,0 +1,54 @@
/*
* 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
*/
#ifndef CALLOUTS_AMD_AGESA_FAM16KB_H
#define CALLOUTS_AMD_AGESA_FAM16KB_H
#include "Porting.h"
#include "AGESA.h"
#define BIOS_HEAP_START_ADDRESS 0x010000000
#define BIOS_HEAP_SIZE 0x30000
#define BSP_STACK_BASE_ADDR 0x30000
typedef struct _BIOS_HEAP_MANAGER {
UINT32 StartOfAllocatedNodes;
UINT32 StartOfFreedNodes;
} BIOS_HEAP_MANAGER;
typedef struct _BIOS_BUFFER_NODE {
UINT32 BufferHandle;
UINT32 BufferSize;
UINT32 NextNodeOffset;
} BIOS_BUFFER_NODE;
AGESA_STATUS fam16kb_AllocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr);
AGESA_STATUS fam16kb_DeallocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr);
AGESA_STATUS fam16kb_LocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr);
AGESA_STATUS fam16kb_GetIdsInitData (UINT32 Func, UINT32 Data, VOID *ConfigPtr);
AGESA_STATUS fam16kb_Reset (UINT32 Func, UINT32 Data, VOID *ConfigPtr);
AGESA_STATUS fam16kb_RunFuncOnAp (UINT32 Func, UINT32 Data, VOID *ConfigPtr);
AGESA_STATUS fam16kb_HookBeforeDQSTraining (UINT32 Func, UINT32 Data, VOID *ConfigPtr);
AGESA_STATUS fam16kb_HookBeforeExitSelfRefresh (UINT32 Func, UINT32 Data, VOID *ConfigPtr);
AGESA_STATUS fam16kb_DefaultRet (UINT32 Func, UINT32 Data, VOID *ConfigPtr);
AGESA_STATUS fam16kb_HookGfxGetVbiosImage(UINT32 Func, UINT32 FchData, VOID *ConfigPrt);
AGESA_STATUS fam16kb_ReadSpd (UINT32 Func, UINT32 Data, VOID *ConfigPtr);
#endif /* CALLOUTS_AMD_AGESA_FAM16KB_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,26 @@
/*
* 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
*/
#ifndef NORTHBRIDGE_AMD_AGESA_FAM16H_H
#define NORTHBRIDGE_AMD_AGESA_FAM16H_H
static struct device_operations pci_domain_ops;
static struct device_operations cpu_bus_ops;
#endif /* NORTHBRIDGE_AMD_AGESA_FAM16H_H */