soc/amd/common/psp: Add command to load fw blobs

An upcoming PSP firmware change will allow coreboot to load the two
SMU firmware blobs (one runs in SRAM and the other in DRAM).  The
traditional method is for the PSP to control most of the process,
e.g. loading the SRAM version prior to releasing the x86 reset.

Add a new command that can instruct the PSP to load a firmware blob
from a location in the flash.

The definition for commands 19 and 1a differ from others in that they
do not use a command/response buffer.  Instead, the PSP will look in
the command/response pointer registers directly for the blob's
address.

BUG=b:66339938

Change-Id: I8431af341930f45ac74f471628b4dc4ede7735f4
Signed-off-by: Marshall Dawson <marshalldawson3rd@gmail.com>
Reviewed-on: https://review.coreboot.org/22056
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
diff --git a/src/soc/amd/common/block/psp/psp.c b/src/soc/amd/common/block/psp/psp.c
index 8b3605e..5aedfc1 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 @@
 
 	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;
+}