soc/amd/common: Add initial support for AMD PSP

Add files for supporting the BIOS->PSP communication not
covered by AGESA. The first command implemented notifies the
PSP that DRAM is ready.

This patch also introduces the amd/common/block directory
structure similar to intel/common/block.

Change-Id: I34b2744b071aa3dfb1071b2aabde32ddb662ab87
Signed-off-by: Marshall Dawson <marshalldawson3rd@gmail.com>
Reviewed-on: https://review.coreboot.org/19753
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Martin Roth <martinroth@google.com>
This commit is contained in:
Marshall Dawson 2017-06-15 16:59:20 -06:00 committed by Martin Roth
parent cfc73952b8
commit 68243a5157
9 changed files with 332 additions and 1 deletions

View File

@ -9,4 +9,6 @@ config SOC_AMD_PI
bool bool
default n default n
source "src/soc/amd/common/block/Kconfig"
endif # SOC_AMD_COMMON endif # SOC_AMD_COMMON

View File

@ -13,4 +13,6 @@ ramstage-y += def_callouts.c
ramstage-y += heapmanager.c ramstage-y += heapmanager.c
ramstage-$(CONFIG_SPI_FLASH) += spi.c ramstage-$(CONFIG_SPI_FLASH) += spi.c
subdirs-$(CONFIG_SOC_AMD_COMMON_BLOCK) += block
endif endif

View File

@ -0,0 +1,11 @@
config SOC_AMD_COMMON_BLOCK
bool
help
SoC driver for AMD common IP code
if SOC_AMD_COMMON_BLOCK
comment "AMD SoC Common IP Code"
source "src/soc/amd/common/block/*/Kconfig"
endif

View File

@ -0,0 +1,7 @@
ifeq ($(CONFIG_SOC_AMD_COMMON_BLOCK),y)
subdirs-y += ./*
CPPFLAGS_common += -I$(src)/soc/amd/common/block/include/
endif

View File

@ -0,0 +1,96 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2017 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.
*/
#ifndef AMD_PSP_H
#define AMD_PSP_H
#include <stdint.h>
#include <Porting.h>
#include <Proc/Psp/PspBaseLib/PspBaseLib.h>
/* x86 to PSP commands */
#define MBOX_BIOS_CMD_DRAM_INFO 0x01
#define MBOX_BIOS_CMD_SMM_INFO 0x02
#define MBOX_BIOS_CMD_SX_INFO 0x03
#define MBOX_BIOS_CMD_RSM_INFO 0x04
#define MBOX_BIOS_CMD_PSP_QUERY 0x05
#define MBOX_BIOS_CMD_BOOT_DONE 0x06
#define MBOX_BIOS_CMD_CLEAR_S3_STS 0x07
#define MBOX_BIOS_CMD_C3_DATA_INFO 0x08
#define MBOX_BIOS_CMD_NOP 0x09
#define MBOX_BIOS_CMD_ABORT 0xfe
/* generic PSP interface status */
#define STATUS_INITIALIZED 0x1
#define STATUS_ERROR 0x2
#define STATUS_TERMINATED 0x4
#define STATUS_HALT 0x8
#define STATUS_RECOVERY 0x10
/* psp_mbox consists of hardware registers beginning at PSPx000070
* mbox_command: BIOS->PSP command, cleared by PSP when complete
* mbox_status: BIOS->PSP interface status
* cmd_response: pointer to command/response buffer
*/
struct psp_mbox {
u32 mbox_command;
u32 mbox_status;
u64 cmd_response; /* definition conflicts w/BKDG but matches agesa */
} __attribute__ ((packed));
/* command/response format, BIOS builds this in memory
* mbox_buffer_header: generic header
* mbox_buffer: command-specific buffer format
*
* AMD reference code aligns and pads all buffers to 32 bytes.
*/
struct mbox_buffer_header {
u32 size; /* total size of buffer */
u32 status; /* command status, filled by PSP if applicable */
} __attribute__ ((packed));
/* command-specific buffer definitions: see NDA document #54267
* todo: create new definitions here for additional c2p_mbox_command commands
*/
struct mbox_default_buffer { /* command-response buffer unused by command */
struct mbox_buffer_header header;
} __attribute__ ((packed,aligned(32)));
/* send_psp_command() error codes */
#define PSPSTS_SUCCESS 0
#define PSPSTS_NOBASE 1
#define PSPSTS_HALTED 2
#define PSPSTS_RECOVERY 3
#define PSPSTS_SEND_ERROR 4
#define PSPSTS_INIT_TIMEOUT 5
#define PSPSTS_CMD_TIMEOUT 6
#if !defined(__SIMPLE_DEVICE__)
#include <device/device.h>
#include <device/pci_def.h>
#define PSP_DEV dev_find_slot(0, PCI_DEVFN(PSP_PCI_DEV, PSP_PCI_FN))
#else
#include <arch/io.h>
#define PSP_DEV PCI_DEV(0, PSP_PCI_DEV, PSP_PCI_FN)
#endif
#define PSP_INIT_TIMEOUT 10000 /* 10 seconds */
#define PSP_CMD_TIMEOUT 1000 /* 1 second */
/* BIOS-to-PSP functions return 0 if successful, else negative value */
int psp_notify_dram(void);
#endif /* AMD_PSP_H */

View File

@ -0,0 +1,6 @@
config SOC_AMD_COMMON_BLOCK_PSP
bool
default n
help
This option builds in the Platform Security Processor initialization
functions.

View File

@ -0,0 +1,2 @@
romstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP) += psp.c
ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP) += psp.c

View File

@ -0,0 +1,203 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2017 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.
*/
#include <arch/io.h>
#include <delay.h>
#include <cbmem.h>
#include <timer.h>
#include <device/pci_def.h>
#include <console/console.h>
#include <amdblocks/psp.h>
static const char *psp_status_nobase = "error: PSP BAR3 not assigned";
static const char *psp_status_halted = "error: PSP in halted state";
static const char *psp_status_recovery = "error: PSP recovery required";
static const char *psp_status_errcmd = "error sending command";
static const char *psp_status_init_timeout = "error: PSP init timeout";
static const char *psp_status_cmd_timeout = "error: PSP command timeout";
static const char *psp_status_noerror = "";
static const char *status_to_string(int err)
{
switch (err) {
case -PSPSTS_NOBASE:
return psp_status_nobase;
case -PSPSTS_HALTED:
return psp_status_halted;
case -PSPSTS_RECOVERY:
return psp_status_recovery;
case -PSPSTS_SEND_ERROR:
return psp_status_errcmd;
case -PSPSTS_INIT_TIMEOUT:
return psp_status_init_timeout;
case -PSPSTS_CMD_TIMEOUT:
return psp_status_cmd_timeout;
default:
return psp_status_noerror;
}
}
static struct psp_mbox *get_mbox_address(void)
{
UINT32 base; /* UINT32 for compatibility with PspBaseLib */
BOOLEAN bar3_status;
uintptr_t baseptr;
bar3_status = GetPspBar3Addr(&base);
if (!bar3_status) {
PspBarInitEarly();
bar3_status = GetPspBar3Addr(&base);
}
if (!bar3_status)
return NULL;
baseptr = base;
return (struct psp_mbox *)(baseptr + PSP_MAILBOX_BASE);
}
static u32 rd_mbox_sts(struct psp_mbox *mbox)
{
return read32(&mbox->mbox_status);
}
static void wr_mbox_cmd(struct psp_mbox *mbox, u32 cmd)
{
write32(&mbox->mbox_command, cmd);
}
static u32 rd_mbox_cmd(struct psp_mbox *mbox)
{
return read32(&mbox->mbox_command);
}
static void wr_mbox_cmd_resp(struct psp_mbox *mbox, void *buffer)
{
write64(&mbox->cmd_response, (uintptr_t)buffer);
}
static u32 rd_resp_sts(struct mbox_default_buffer *buffer)
{
return read32(&buffer->header.status);
}
static int wait_initialized(struct psp_mbox *mbox)
{
struct stopwatch sw;
stopwatch_init_msecs_expire(&sw, PSP_INIT_TIMEOUT);
do {
if (rd_mbox_sts(mbox) & STATUS_INITIALIZED)
return 0;
} while (!stopwatch_expired(&sw));
return -PSPSTS_INIT_TIMEOUT;
}
static int wait_command(struct psp_mbox *mbox)
{
struct stopwatch sw;
stopwatch_init_msecs_expire(&sw, PSP_CMD_TIMEOUT);
do {
if (!rd_mbox_cmd(mbox))
return 0;
} while (!stopwatch_expired(&sw));
return -PSPSTS_CMD_TIMEOUT;
}
static int send_psp_command(u32 command, void *buffer)
{
u32 command_reg;
int status = 0;
struct psp_mbox *mbox = get_mbox_address();
if (!mbox)
return -PSPSTS_NOBASE;
command_reg = pci_read_config32(PSP_DEV, PCI_COMMAND);
pci_write_config32(PSP_DEV, PCI_COMMAND, command_reg |
PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
/* check for PSP error conditions */
if (rd_mbox_sts(mbox) & STATUS_HALT) {
status = -PSPSTS_HALTED;
goto exit;
}
if (rd_mbox_sts(mbox) & STATUS_RECOVERY) {
status = -PSPSTS_RECOVERY;
goto exit;
}
/* PSP must be finished with init and ready to accept a command */
if (wait_initialized(mbox)) {
status = -PSPSTS_INIT_TIMEOUT;
goto exit;
}
if (wait_command(mbox)) {
status = -PSPSTS_CMD_TIMEOUT;
goto exit;
}
/* set address of command-response buffer and write command register */
wr_mbox_cmd_resp(mbox, buffer);
wr_mbox_cmd(mbox, command);
/* PSP clears command register when complete */
if (wait_command(mbox)) {
status = -PSPSTS_CMD_TIMEOUT;
goto exit;
}
/* check delivery status */
if (rd_mbox_sts(mbox) & (STATUS_ERROR | STATUS_TERMINATED)) {
status = -PSPSTS_SEND_ERROR;
goto exit;
}
exit:
/* restore command register to original value */
pci_write_config32(PSP_DEV, PCI_COMMAND, command_reg);
return status;
}
/*
* Notify the PSP that DRAM is present. Upon receiving this command, the PSP
* will load its OS into fenced DRAM that is not accessible to the x86 cores.
*/
int psp_notify_dram(void)
{
struct mbox_default_buffer buffer;
int cmd_status;
printk(BIOS_DEBUG, "PSP: Notify that DRAM is available... ");
buffer.header.size = sizeof(struct mbox_default_buffer);
buffer.header.status = 0; /* PSP does not report status for this cmd */
cmd_status = send_psp_command(MBOX_BIOS_CMD_DRAM_INFO, &buffer);
/* buffer's status shouldn't change but report it if it does */
if (rd_resp_sts(&buffer))
printk(BIOS_DEBUG, "buffer status=0x%x ",
rd_resp_sts(&buffer));
if (cmd_status)
printk(BIOS_DEBUG, "%s\n", status_to_string(cmd_status));
else
printk(BIOS_DEBUG, "OK\n");
return cmd_status;
}

View File

@ -40,8 +40,10 @@ config CPU_SPECIFIC_OPTIONS
select TSC_CONSTANT_RATE select TSC_CONSTANT_RATE
select SPI_FLASH if HAVE_ACPI_RESUME select SPI_FLASH if HAVE_ACPI_RESUME
select TSC_SYNC_LFENCE select TSC_SYNC_LFENCE
select SOC_AMD_COMMON
select SOC_AMD_PI select SOC_AMD_PI
select SOC_AMD_COMMON
select SOC_AMD_COMMON_BLOCK
select SOC_AMD_COMMON_BLOCK_PSP
config UDELAY_LAPIC_FIXED_FSB config UDELAY_LAPIC_FIXED_FSB
int int