summaryrefslogtreecommitdiff
path: root/src/drivers/amd/agesa/oem_s3.c
diff options
context:
space:
mode:
authorKyösti Mälkki <kyosti.malkki@gmail.com>2017-09-08 07:14:17 +0300
committerKyösti Mälkki <kyosti.malkki@gmail.com>2017-09-26 10:07:07 +0000
commitd4955f0ade18cafde4a3ea20885eb9fbdc5b4514 (patch)
tree71b6e96cc01fbb58d6bfdd50b6c55e431634724d /src/drivers/amd/agesa/oem_s3.c
parent0f6c0b1a6f062be702fd0b10a6c591c42f982b63 (diff)
downloadcoreboot-d4955f0ade18cafde4a3ea20885eb9fbdc5b4514.tar.xz
AGESA: Move API interface under drivers/
New AGESA support files will be used for binaryPI platforms as well. Furthermore, some of those should move from split nb/ sb/ directories to soc/, so move support files for the API under drivers/. Change-Id: I549788091de91f61de8b9adc223d52ffb5732235 Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com> Reviewed-on: https://review.coreboot.org/21455 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Diffstat (limited to 'src/drivers/amd/agesa/oem_s3.c')
-rw-r--r--src/drivers/amd/agesa/oem_s3.c165
1 files changed, 165 insertions, 0 deletions
diff --git a/src/drivers/amd/agesa/oem_s3.c b/src/drivers/amd/agesa/oem_s3.c
new file mode 100644
index 0000000000..1ca6e5b2f6
--- /dev/null
+++ b/src/drivers/amd/agesa/oem_s3.c
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+#include <spi-generic.h>
+#include <spi_flash.h>
+#include <string.h>
+#include <cbmem.h>
+#include <program_loading.h>
+#include <northbridge/amd/agesa/state_machine.h>
+#include <AGESA.h>
+#include <northbridge/amd/agesa/agesa_helper.h>
+
+typedef enum {
+ S3DataTypeNonVolatile = 0, ///< NonVolatile Data Type
+ S3DataTypeMTRR ///< MTRR storage
+} S3_DATA_TYPE;
+
+/* The size needs to be 4k aligned, which is the sector size of most flashes. */
+#define S3_DATA_MTRR_SIZE 0x1000
+#define S3_DATA_NONVOLATILE_SIZE 0x1000
+
+#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME) && \
+ (S3_DATA_MTRR_SIZE + S3_DATA_NONVOLATILE_SIZE) > CONFIG_S3_DATA_SIZE
+#error "Please increase the value of S3_DATA_SIZE"
+#endif
+
+static void get_s3nv_data(S3_DATA_TYPE S3DataType, uintptr_t *pos, uintptr_t *len)
+{
+ /* FIXME: Find file from CBFS. */
+ u32 s3_data = CONFIG_S3_DATA_POS;
+
+ switch (S3DataType) {
+ case S3DataTypeMTRR:
+ *pos = s3_data;
+ *len = S3_DATA_MTRR_SIZE;
+ break;
+ case S3DataTypeNonVolatile:
+ *pos = s3_data + S3_DATA_MTRR_SIZE;
+ *len = S3_DATA_NONVOLATILE_SIZE;
+ break;
+ default:
+ *pos = 0;
+ *len = 0;
+ break;
+ }
+}
+
+AGESA_STATUS OemInitResume(AMD_S3_PARAMS *dataBlock)
+{
+ uintptr_t pos, size;
+ get_s3nv_data(S3DataTypeNonVolatile, &pos, &size);
+
+ u32 len = *(u32*)pos;
+
+ /* Test for uninitialized s3nv data in SPI. */
+ if (len == 0 || len == (u32)-1ULL)
+ return AGESA_FATAL;
+
+ dataBlock->NvStorageSize = len;
+ dataBlock->NvStorage = (void *) (pos + sizeof(u32));
+ return AGESA_SUCCESS;
+}
+
+AGESA_STATUS OemS3LateRestore(AMD_S3_PARAMS *dataBlock)
+{
+ char *heap = cbmem_find(CBMEM_ID_RESUME_SCRATCH);
+ if (heap == NULL)
+ return AGESA_FATAL;
+
+ printk(BIOS_DEBUG, "Using resume HEAP at %08x\n",
+ (unsigned int)(uintptr_t) heap);
+
+ /* Return allocated CBMEM size, we do not keep track of
+ * how much was actually used.
+ */
+ dataBlock->VolatileStorageSize = HIGH_MEMORY_SCRATCH;
+ dataBlock->VolatileStorage = heap;
+ return AGESA_SUCCESS;
+}
+
+#if ENV_RAMSTAGE
+
+static int spi_SaveS3info(u32 pos, u32 size, u8 *buf, u32 len)
+{
+#if IS_ENABLED(CONFIG_SPI_FLASH)
+ struct spi_flash flash;
+
+ spi_init();
+ if (spi_flash_probe(0, 0, &flash))
+ return -1;
+
+ spi_flash_volatile_group_begin(&flash);
+
+ spi_flash_erase(&flash, pos, size);
+ spi_flash_write(&flash, pos, sizeof(len), &len);
+ spi_flash_write(&flash, pos + sizeof(len), len, buf);
+
+ spi_flash_volatile_group_end(&flash);
+ return 0;
+#else
+ return -1;
+#endif
+}
+
+static u8 MTRRStorage[S3_DATA_MTRR_SIZE];
+
+AGESA_STATUS OemS3Save(AMD_S3_PARAMS *dataBlock)
+{
+ u32 MTRRStorageSize = 0;
+ uintptr_t pos, size;
+
+ romstage_ram_stack_base(HIGH_ROMSTAGE_STACK_SIZE, ROMSTAGE_STACK_CBMEM);
+
+ /* To be consumed in AmdInitResume. */
+ get_s3nv_data(S3DataTypeNonVolatile, &pos, &size);
+ if (size && dataBlock->NvStorageSize)
+ spi_SaveS3info(pos, size, dataBlock->NvStorage,
+ dataBlock->NvStorageSize);
+ else
+ printk(BIOS_EMERG,
+ "Error: Cannot store memory training results in SPI.\n"
+ "Error: S3 resume will not be possible.\n"
+ );
+
+ /* To be consumed in AmdS3LateRestore. */
+ char *heap = cbmem_add(CBMEM_ID_RESUME_SCRATCH, HIGH_MEMORY_SCRATCH);
+ if (heap) {
+ memset(heap, 0, HIGH_MEMORY_SCRATCH);
+ memcpy(heap, dataBlock->VolatileStorage, dataBlock->VolatileStorageSize);
+ }
+
+ /* Collect MTRR setup. */
+ backup_mtrr(MTRRStorage, &MTRRStorageSize);
+
+ /* To be consumed in restore_mtrr, CPU enumeration in ramstage. */
+ get_s3nv_data(S3DataTypeMTRR, &pos, &size);
+ if (size && MTRRStorageSize)
+ spi_SaveS3info(pos, size, MTRRStorage, MTRRStorageSize);
+
+ return AGESA_SUCCESS;
+}
+
+#endif /* ENV_RAMSTAGE */
+
+const void *OemS3Saved_MTRR_Storage(void)
+{
+ uintptr_t pos, size;
+ get_s3nv_data(S3DataTypeMTRR, &pos, &size);
+ if (!size)
+ return NULL;
+
+ return (void*)(pos + sizeof(UINT32));
+}