diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/soc/amd/common/block/include/amdblocks/psp.h | 14 | ||||
-rw-r--r-- | src/soc/amd/common/block/psp/Kconfig | 12 | ||||
-rw-r--r-- | src/soc/amd/common/block/psp/psp.c | 57 |
3 files changed, 83 insertions, 0 deletions
diff --git a/src/soc/amd/common/block/include/amdblocks/psp.h b/src/soc/amd/common/block/include/amdblocks/psp.h index d210498502..74ea73f7f7 100644 --- a/src/soc/amd/common/block/include/amdblocks/psp.h +++ b/src/soc/amd/common/block/include/amdblocks/psp.h @@ -32,6 +32,8 @@ #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_SMU_FW 0x19 +#define MBOX_BIOS_CMD_SMU_FW2 0x1a #define MBOX_BIOS_CMD_ABORT 0xfe /* generic PSP interface status */ @@ -79,11 +81,23 @@ struct mbox_default_buffer { /* command-response buffer unused by command */ #define PSPSTS_SEND_ERROR 4 #define PSPSTS_INIT_TIMEOUT 5 #define PSPSTS_CMD_TIMEOUT 6 +/* other error codes */ +#define PSPSTS_UNSUPPORTED 7 +#define PSPSTS_INVALID_NAME 8 +#define PSPSTS_INVALID_BLOB 9 #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); +/* + * type: identical to the corresponding PSP command, e.g. pass + * MBOX_BIOS_CMD_SMU_FW2 to load SMU FW2 blob. + * name: cbfs file name + */ +int psp_load_named_blob(int type, const char *name); + #endif /* __AMD_PSP_H__ */ diff --git a/src/soc/amd/common/block/psp/Kconfig b/src/soc/amd/common/block/psp/Kconfig index 69958f21aa..0517a2f33f 100644 --- a/src/soc/amd/common/block/psp/Kconfig +++ b/src/soc/amd/common/block/psp/Kconfig @@ -4,3 +4,15 @@ config SOC_AMD_COMMON_BLOCK_PSP help This option builds in the Platform Security Processor initialization functions. + +config SOC_AMD_PSP_SELECTABLE_SMU_FW + bool + default n + help + Some PSP implementations allow storing SMU firmware into cbfs and + calling the PSP to load the blobs at the proper time. + + The soc/<codename> should select this if its PSP supports the feature + and each mainboard can choose to select an appropriate fanless or + fanned set of blobs. Ask your AMD representative whether your APU + is considered fanless. diff --git a/src/soc/amd/common/block/psp/psp.c b/src/soc/amd/common/block/psp/psp.c index 8b3605e6fa..5aedfc138f 100644 --- a/src/soc/amd/common/block/psp/psp.c +++ b/src/soc/amd/common/block/psp/psp.c @@ -14,6 +14,8 @@ */ #include <arch/io.h> +#include <cbfs.h> +#include <region_file.h> #include <timer.h> #include <device/pci_def.h> #include <console/console.h> @@ -199,3 +201,58 @@ int psp_notify_dram(void) return cmd_status; } + +/* + * Tell the PSP to load a firmware blob from a location in the BIOS image. + */ +static int psp_load_blob(int type, void *addr) +{ + int cmd_status; + + if (!IS_ENABLED(CONFIG_SOC_AMD_PSP_SELECTABLE_SMU_FW)) { + printk(BIOS_ERR, "BUG: Selectable firmware is not supported\n"); + return PSPSTS_UNSUPPORTED; + } + + /* only two types currently supported */ + if (type != MBOX_BIOS_CMD_SMU_FW && type != MBOX_BIOS_CMD_SMU_FW2) { + printk(BIOS_ERR, "BUG: Invalid PSP blob type %x\n", type); + return PSPSTS_INVALID_BLOB; + } + + printk(BIOS_DEBUG, "PSP: Load blob type %x from @%p... ", type, addr); + + /* Blob commands use the buffer registers as data, not pointer to buf */ + cmd_status = send_psp_command(type, addr); + + if (cmd_status) + printk(BIOS_DEBUG, "%s\n", status_to_string(cmd_status)); + else + printk(BIOS_DEBUG, "OK\n"); + + return cmd_status; +} + +int psp_load_named_blob(int type, const char *name) +{ + void *blob; + struct cbfsf cbfs_file; + struct region_device rdev; + int r; + + if (cbfs_boot_locate(&cbfs_file, name, NULL)) { + printk(BIOS_ERR, "BUG: Cannot locate blob for PSP loading\n"); + return PSPSTS_INVALID_NAME; + } + + cbfs_file_data(&rdev, &cbfs_file); + blob = rdev_mmap_full(&rdev); + if (blob) { + r = psp_load_blob(type, blob); + rdev_munmap(&rdev, blob); + } else { + printk(BIOS_ERR, "BUG: Cannot map blob for PSP loading\n"); + return PSPSTS_INVALID_NAME; + } + return r; +} |