drivers/intel/fsp2_0: add option to compress FSP-S in cbfs

Allow the ability for chipset or mainboard to choose to
compress FSP-S in cbfs using LZMA or LZ4 routines. To accomplish
this fsp_load_component() is added as an assist for performing
the necessary logic and allow the caller to provide the destination
selection. Since the main cbfs decompression paths are utilized add
the appropriate checks for including compression algorithms under
the FSP-S compression options.

On picasso FSP-S (debug builds) the following savings were measured:

no-compression:
	fsps.bin	327680	none
FSP_COMPRESS_FSP_S_LZ4:
	fsps.bin	98339	LZ4 (327680 decompressed)	-70%
FSP_COMPRESS_FSP_S_LZMA:
	fsps.bin	71275 	LZMA (327680 decompressed)	-78%

BUG=b:155322763,b:150746858,b:152909132

Change-Id: I8aa5d8c1cbaf4d08f38a918a9031a2570bc5247e
Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/41449
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Furquan Shaikh <furquan@google.com>
diff --git a/src/drivers/intel/fsp2_0/util.c b/src/drivers/intel/fsp2_0/util.c
index 4050862..3b7516a 100644
--- a/src/drivers/intel/fsp2_0/util.c
+++ b/src/drivers/intel/fsp2_0/util.c
@@ -1,9 +1,13 @@
 /* SPDX-License-Identifier: GPL-2.0-or-later */
 
 #include <device/mmio.h>
+#include <cbfs.h>
 #include <cf9_reset.h>
+#include <commonlib/bsd/compression.h>
+#include <commonlib/fsp.h>
 #include <console/console.h>
 #include <fsp/util.h>
+#include <lib.h>
 #include <string.h>
 #include <types.h>
 
@@ -114,3 +118,68 @@
 		break;
 	}
 }
+
+static void *fsp_get_dest_and_load(struct fsp_load_descriptor *fspld, size_t size,
+				const struct region_device *source_rdev,
+				uint32_t compression_algo)
+{
+	void *dest;
+
+	if (fspld->get_destination(fspld, &dest, size, source_rdev) < 0) {
+		printk(BIOS_ERR, "FSP Destination not obtained.\n");
+		return NULL;
+	}
+
+	if (cbfs_load_and_decompress(source_rdev, 0, region_device_sz(source_rdev),
+			dest, size, compression_algo) != size) {
+		printk(BIOS_ERR, "Failed to load FSP component.\n");
+		return NULL;
+	}
+
+	if (fsp_component_relocate((uintptr_t)dest, dest, size) < 0) {
+		printk(BIOS_ERR, "Unable to relocate FSP component!\n");
+		return NULL;
+	}
+
+	return dest;
+}
+
+/* Load the FSP component described by fsp_load_descriptor from cbfs. The FSP
+ * header object will be validated and filled in on successful load. */
+enum cb_err fsp_load_component(struct fsp_load_descriptor *fspld, struct fsp_header *hdr)
+{
+	struct cbfsf file_desc;
+	uint32_t compression_algo;
+	size_t output_size;
+	void *dest;
+	struct region_device source_rdev;
+	struct prog *fsp_prog = &fspld->fsp_prog;
+
+	if (fspld->get_destination == NULL)
+		return CB_ERR;
+
+	if (cbfs_boot_locate(&file_desc, prog_name(fsp_prog), &fsp_prog->cbfs_type) < 0)
+		return CB_ERR;
+
+	if (cbfsf_decompression_info(&file_desc, &compression_algo, &output_size) < 0)
+		return CB_ERR;
+
+	cbfs_file_data(&source_rdev, &file_desc);
+
+	dest = fsp_get_dest_and_load(fspld, output_size, &source_rdev, compression_algo);
+
+	if (dest == NULL)
+		return CB_ERR;
+
+	prog_set_area(fsp_prog, dest, output_size);
+
+	if (fsp_validate_component(hdr, prog_rdev(fsp_prog)) != CB_SUCCESS) {
+		printk(BIOS_ERR, "Invalid FSP header after load!\n");
+		return CB_ERR;
+	}
+
+	/* Signal that FSP component has been loaded. */
+	prog_segment_loaded(hdr->image_base, hdr->image_size, SEG_FINAL);
+
+	return CB_SUCCESS;
+}