Files
system76-coreboot/src/cpu/amd/agesa/s3_resume.c
Martin Roth 3316cf2ff8 Claim the SPI bus before writes if the IMC ROM is present
The SB800 and Hudson now support adding the IMC ROM which runs from the same
chip as coreboot.  When the IMC is running, write or erase commands sent to
the spi bus will fail, and the IMC will die.  To fix this, we send a request
to the IMC to stop fetching from the SPI rom while we write to it. This
process (in one form or another) is required for writes to the SPI bus while
the IMC is running.

Because the IMC can take up to 500ms to respond every time we claim the
bus, this patch tries to keep the number of times we need to do that to a
minimum.  We only need to claim the bus on writes, and using a counter for
the semaphore allows us to call in once to claim the bus at the beginning
of a number of transactions and it will stay claimed until we release it
at the end of the transactions.

Claim() - takes up to 500ms hit
    claim() - no delay
        erase()
    release()
    claim() - no delay
        write()
    release()
Release()

Change-Id: I4e003c5122a2ed47abce57ab8b92dee6aa4713ed
Signed-off-by: Martin Roth <martin@se-eng.com>
Reviewed-on: http://review.coreboot.org/1976
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Georgi <patrick@georgi-clan.de>
2012-12-12 22:34:16 +01:00

342 lines
8.1 KiB
C

/*
* 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 "AGESA.h"
#include "amdlib.h"
#include <console/console.h>
#include <cpu/x86/msr.h>
#include <cpu/x86/mtrr.h>
#include <cpu/amd/mtrr.h>
#include <cpu/x86/cache.h>
#if CONFIG_WRITE_HIGH_TABLES
#include <cbmem.h>
#endif
#include <device/device.h>
#include <device/pci.h>
#ifndef __PRE_RAM__
#include <device/pci_ops.h>
#endif
#include <arch/io.h>
#include <arch/acpi.h>
#include <string.h>
#include "Porting.h"
#include "BiosCallOuts.h"
#include "s3_resume.h"
#include "agesawrapper.h"
#ifndef __PRE_RAM__
#include <spi.h>
#include <spi_flash.h>
#endif
void restore_mtrr(void)
{
u32 msr;
volatile UINT32 *msrPtr = (volatile UINT32 *)S3_DATA_MTRR_POS;
msr_t msr_data;
printk(BIOS_SPEW, "%s\n", __func__);
disable_cache();
/* Enable access to AMD RdDram and WrDram extension bits */
msr_data = rdmsr(SYS_CFG);
msr_data.lo |= SYSCFG_MSR_MtrrFixDramModEn;
wrmsr(SYS_CFG, msr_data);
/* Now restore the Fixed MTRRs */
msr_data.lo = *msrPtr;
msrPtr ++;
msr_data.hi = *msrPtr;
msrPtr ++;
wrmsr(0x250, msr_data);
msr_data.lo = *msrPtr;
msrPtr ++;
msr_data.hi = *msrPtr;
msrPtr ++;
wrmsr(0x258, msr_data);
msr_data.lo = *msrPtr;
msrPtr ++;
msr_data.hi = *msrPtr;
msrPtr ++;
wrmsr(0x259, msr_data);
for (msr = 0x268; msr <= 0x26F; msr++) {
msr_data.lo = *msrPtr;
msrPtr ++;
msr_data.hi = *msrPtr;
msrPtr ++;
wrmsr(msr, msr_data);
}
/* Disable access to AMD RdDram and WrDram extension bits */
msr_data = rdmsr(SYS_CFG);
msr_data.lo &= ~SYSCFG_MSR_MtrrFixDramModEn;
wrmsr(SYS_CFG, msr_data);
/* Restore the Variable MTRRs */
for (msr = 0x200; msr <= 0x20F; msr++) {
msr_data.lo = *msrPtr;
msrPtr ++;
msr_data.hi = *msrPtr;
msrPtr ++;
wrmsr(msr, msr_data);
}
/* Restore SYSCFG MTRR */
msr_data.lo = *msrPtr;
msrPtr ++;
msr_data.hi = *msrPtr;
msrPtr ++;
wrmsr(SYS_CFG, msr_data);
}
inline void *backup_resume(void)
{
unsigned long high_ram_base;
void *resume_backup_memory;
/* Start address of high memory tables */
high_ram_base = (u32) get_cbmem_toc();
/*
* printk(BIOS_DEBUG, "CBMEM TOC is at: %x\n", (u32_t)high_ram_base);
* printk(BIOS_DEBUG, "CBMEM TOC 0-size:%x\n ",(u32_t)(high_ram_base + HIGH_MEMORY_SIZE + 4096));
*/
cbmem_reinit((u64) high_ram_base);
resume_backup_memory = cbmem_find(CBMEM_ID_RESUME);
if (((u32) resume_backup_memory == 0)
|| ((u32) resume_backup_memory == -1)) {
printk(BIOS_ERR, "Error: resume_backup_memory: %x\n",
(u32) resume_backup_memory);
for (;;) ;
}
return resume_backup_memory;
}
void move_stack_high_mem(void)
{
void *high_stack;
high_stack = cbmem_find(CBMEM_ID_RESUME_SCRATCH);
memcpy(high_stack, (void *)BSP_STACK_BASE_ADDR,
(CONFIG_HIGH_SCRATCH_MEMORY_SIZE - BIOS_HEAP_SIZE));
__asm__
volatile ("add %0, %%esp; add %0, %%ebp; invd"::"g"
(high_stack - BSP_STACK_BASE_ADDR)
:);
}
void OemAgesaSaveMtrr(void)
{
#ifndef __PRE_RAM__
msr_t msr_data;
u32 nvram_pos = S3_DATA_MTRR_POS;
u32 i;
struct spi_flash *flash;
spi_init();
flash = spi_flash_probe(0, 0, 0, 0);
if (!flash) {
printk(BIOS_DEBUG, "Could not find SPI device\n");
return;
}
flash->spi->rw = SPI_WRITE_FLAG;
spi_claim_bus(flash->spi);
/* Enable access to AMD RdDram and WrDram extension bits */
msr_data = rdmsr(SYS_CFG);
msr_data.lo |= SYSCFG_MSR_MtrrFixDramModEn;
wrmsr(SYS_CFG, msr_data);
/* Fixed MTRRs */
msr_data = rdmsr(0x250);
flash->write(flash, nvram_pos, 4, &msr_data.lo);
nvram_pos += 4;
flash->write(flash, nvram_pos, 4, &msr_data.hi);
nvram_pos += 4;
msr_data = rdmsr(0x258);
flash->write(flash, nvram_pos, 4, &msr_data.lo);
nvram_pos += 4;
flash->write(flash, nvram_pos, 4, &msr_data.hi);
nvram_pos += 4;
msr_data = rdmsr(0x259);
flash->write(flash, nvram_pos, 4, &msr_data.lo);
nvram_pos += 4;
flash->write(flash, nvram_pos, 4, &msr_data.hi);
nvram_pos += 4;
for (i = 0x268; i < 0x270; i++) {
msr_data = rdmsr(i);
flash->write(flash, nvram_pos, 4, &msr_data.lo);
nvram_pos += 4;
flash->write(flash, nvram_pos, 4, &msr_data.hi);
nvram_pos += 4;
}
/* Disable access to AMD RdDram and WrDram extension bits */
msr_data = rdmsr(SYS_CFG);
msr_data.lo &= ~SYSCFG_MSR_MtrrFixDramModEn;
wrmsr(SYS_CFG, msr_data);
/* Variable MTRRs */
for (i = 0x200; i < 0x210; i++) {
msr_data = rdmsr(i);
flash->write(flash, nvram_pos, 4, &msr_data.lo);
nvram_pos += 4;
flash->write(flash, nvram_pos, 4, &msr_data.hi);
nvram_pos += 4;
}
/* SYS_CFG */
msr_data = rdmsr(0xC0010010);
flash->write(flash, nvram_pos, 4, &msr_data.lo);
nvram_pos += 4;
flash->write(flash, nvram_pos, 4, &msr_data.hi);
nvram_pos += 4;
/* TOM */
msr_data = rdmsr(0xC001001A);
flash->write(flash, nvram_pos, 4, &msr_data.lo);
nvram_pos += 4;
flash->write(flash, nvram_pos, 4, &msr_data.hi);
nvram_pos += 4;
/* TOM2 */
msr_data = rdmsr(0xC001001D);
flash->write(flash, nvram_pos, 4, &msr_data.lo);
nvram_pos += 4;
flash->write(flash, nvram_pos, 4, &msr_data.hi);
nvram_pos += 4;
flash->spi->rw = SPI_WRITE_FLAG;
spi_release_bus(flash->spi);
#endif
}
void OemAgesaGetS3Info(S3_DATA_TYPE S3DataType, u32 *DataSize, void **Data)
{
AMD_CONFIG_PARAMS StdHeader;
if (S3DataType == S3DataTypeNonVolatile) {
*Data = (void *)S3_DATA_NONVOLATILE_POS;
*DataSize = *(UINTN *) (*Data);
*Data += 4;
} else {
*DataSize = *(UINTN *) S3_DATA_VOLATILE_POS;
*Data = (void *) GetHeapBase(&StdHeader);
memcpy((void *)(*Data), (void *)(S3_DATA_VOLATILE_POS + 4), *DataSize);
}
}
#ifndef __PRE_RAM__
u32 OemAgesaSaveS3Info(S3_DATA_TYPE S3DataType, u32 DataSize, void *Data)
{
u32 pos = S3_DATA_VOLATILE_POS;
u32 data;
u32 nvram_pos;
struct spi_flash *flash;
if (S3DataType == S3DataTypeNonVolatile) {
pos = S3_DATA_NONVOLATILE_POS;
} else { /* S3DataTypeVolatile */
pos = S3_DATA_VOLATILE_POS;
}
spi_init();
flash = spi_flash_probe(0, 0, 0, 0);
if (!flash) {
printk(BIOS_DEBUG, "Could not find SPI device\n");
/* Dont make flow stop. */
return AGESA_SUCCESS;
}
flash->spi->rw = SPI_WRITE_FLAG;
spi_claim_bus(flash->spi);
if (S3DataType == S3DataTypeNonVolatile) {
flash->erase(flash, S3_DATA_NONVOLATILE_POS, 0x1000);
} else {
flash->erase(flash, S3_DATA_VOLATILE_POS, 0x6000);
}
nvram_pos = 0;
flash->write(flash, nvram_pos + pos, sizeof(DataSize), &DataSize);
for (nvram_pos = 0; nvram_pos < DataSize; nvram_pos += 4) {
data = *(u32 *) (Data + nvram_pos);
flash->write(flash, nvram_pos + pos + 4, sizeof(u32), (u32 *)(Data + nvram_pos));
}
flash->spi->rw = SPI_WRITE_FLAG;
spi_release_bus(flash->spi);
return AGESA_SUCCESS;
}
#endif
void set_resume_cache(void)
{
msr_t msr;
/* disable fixed mtrr for now, it will be enabled by mtrr restore */
msr = rdmsr(SYSCFG_MSR);
msr.lo &= ~(SYSCFG_MSR_MtrrFixDramEn | SYSCFG_MSR_MtrrFixDramModEn);
wrmsr(SYSCFG_MSR, msr);
/* Enable caching for 0 - coreboot ram using variable mtrr */
msr.lo = 0 | MTRR_TYPE_WRBACK;
msr.hi = 0;
wrmsr(MTRRphysBase_MSR(0), msr);
msr.lo = ~(CONFIG_RAMTOP - 1) | MTRRphysMaskValid;
msr.hi = (1 << (CONFIG_CPU_ADDR_BITS - 32)) - 1;
wrmsr(MTRRphysMask_MSR(0), msr);
/* Set the default memory type and disable fixed and enable variable MTRRs */
msr.hi = 0;
msr.lo = (1 << 11);
wrmsr(MTRRdefType_MSR, msr);
enable_cache();
}
void s3_resume(void)
{
int status;
printk(BIOS_DEBUG, "agesawrapper_amds3laterestore ");
status = agesawrapper_amds3laterestore();
if (status)
printk(BIOS_DEBUG, "error level: %x \n", (u32) status);
else
printk(BIOS_DEBUG, "passed.\n");
}