diff --git a/src/soc/intel/baytrail/refcode.c b/src/soc/intel/baytrail/refcode.c index 9b5aa6790e..f746358faf 100644 --- a/src/soc/intel/baytrail/refcode.c +++ b/src/soc/intel/baytrail/refcode.c @@ -17,19 +17,113 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include +#include #include #include #include #include +#include #include #include +static inline int is_s3_resume(void) +{ +#if CONFIG_HAVE_ACPI_RESUME + return acpi_slp_type == 3; +#else + return 0; +#endif +} + +static inline struct ramstage_cache *next_cache(struct ramstage_cache *c) +{ + return (struct ramstage_cache *)&c->program[c->size]; +} + static void ABI_X86 send_to_console(unsigned char b) { console_tx_byte(b); } +static efi_wrapper_entry_t load_refcode_from_cache(void) +{ + struct ramstage_cache *c; + long cache_size; + + printk(BIOS_DEBUG, "refcode loading from cache.\n"); + + c = ramstage_cache_location(&cache_size); + + if (!ramstage_cache_is_valid(c)) { + printk(BIOS_DEBUG, "Invalid ramstage cache descriptor.\n"); + return NULL; + } + + c = next_cache(c); + if (!ramstage_cache_is_valid(c)) { + printk(BIOS_DEBUG, "Invalid refcode cache descriptor.\n"); + return NULL; + } + + printk(BIOS_DEBUG, "Loading cached reference code from 0x%08x(%x)\n", + c->load_address, c->size); + memcpy((void *)c->load_address, &c->program[0], c->size); + + return (efi_wrapper_entry_t)c->entry_point; +} + +static void cache_refcode(const struct rmod_stage_load *rsl) +{ + struct ramstage_cache *c; + long cache_size; + + c = ramstage_cache_location(&cache_size); + + if (!ramstage_cache_is_valid(c)) { + printk(BIOS_DEBUG, "No place to cache reference code.\n"); + return; + } + + /* Determine how much remaining cache available. */ + cache_size -= c->size + sizeof(*c); + + if (cache_size < (sizeof(*c) + cbmem_entry_size(rsl->cbmem_entry))) { + printk(BIOS_DEBUG, "Not enough cache space for ref code.\n"); + return; + } + + c = next_cache(c); + c->magic = RAMSTAGE_CACHE_MAGIC; + c->entry_point = (uint32_t)rsl->entry; + c->load_address = (uint32_t)cbmem_entry_start(rsl->cbmem_entry); + c->size = cbmem_entry_size(rsl->cbmem_entry);; + + printk(BIOS_DEBUG, "Caching refcode at 0x%p(%x)\n", + &c->program[0], c->size); + memcpy(&c->program[0], (void *)c->load_address, c->size); +} + +static efi_wrapper_entry_t load_refcode_from_cbfs(void) +{ + struct rmod_stage_load refcode = { + .cbmem_id = CBMEM_ID_REFCODE, + .name = CONFIG_CBFS_PREFIX "/refcode", + }; + + printk(BIOS_DEBUG, "refcode loading from cbfs.\n"); + + if (rmodule_stage_load_from_cbfs(&refcode) || refcode.entry == NULL) { + printk(BIOS_DEBUG, "Error loading reference code.\n"); + return NULL; + } + + cache_refcode(&refcode); + + return refcode.entry; +} + void baytrail_run_reference_code(void) { int ret; @@ -38,18 +132,17 @@ void baytrail_run_reference_code(void) .version = EFI_WRAPPER_VER, .console_out = send_to_console, }; - struct rmod_stage_load refcode = { - .cbmem_id = CBMEM_ID_REFCODE, - .name = CONFIG_CBFS_PREFIX "/refcode", - }; - if (rmodule_stage_load_from_cbfs(&refcode) || refcode.entry == NULL) { - printk(BIOS_DEBUG, "Error loading reference code.\n"); - return; + if (is_s3_resume()) { + entry = load_refcode_from_cache(); + } else { + entry = load_refcode_from_cbfs(); } + if (entry == NULL) + return; + wrp.tsc_ticks_per_microsecond = tsc_freq_mhz(); - entry = refcode.entry; /* Call into reference code. */ ret = entry(&wrp);