blob: 1a1818ffee35bb23ce08a682f3379a5826e15950 [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0-only */
#include <arch/romstage.h>
#include <cbmem.h>
#include <console/console.h>
#include <commonlib/helpers.h>
#include <cpu/amd/mtrr.h>
#include <cpu/cpu.h>
#include <cpu/x86/msr.h>
#include <cpu/x86/mtrr.h>
#include <northbridge/amd/agesa/agesa_helper.h>
#include <romstage_handoff.h>
static void set_range_uc(u32 base, u32 size)
{
int i, max_var_mtrrs;
msr_t msr;
max_var_mtrrs = get_var_mtrr_count();
for (i = 0; i < max_var_mtrrs; i++) {
msr = rdmsr(MTRR_PHYS_MASK(i));
if (!(msr.lo & MTRR_PHYS_MASK_VALID))
break;
}
if (i == max_var_mtrrs)
die("Run out of unused MTRRs\n");
msr.hi = 0;
msr.lo = base | MTRR_TYPE_UNCACHEABLE;
wrmsr(MTRR_PHYS_BASE(i), msr);
msr.hi = (1 << (cpu_phys_address_size() - 32)) - 1;
msr.lo = ~(size - 1) | MTRR_PHYS_MASK_VALID;
wrmsr(MTRR_PHYS_MASK(i), msr);
}
void fixup_cbmem_to_UC(int s3resume)
{
if (s3resume)
return;
/* For normal path, INIT_POST has returned with all
* memory set WB cacheable. But we need CBMEM as UC
* to make CAR teardown with invalidation without
* writeback possible.
*/
uintptr_t top_of_ram = (uintptr_t) cbmem_top();
top_of_ram = ALIGN_UP(top_of_ram, 4 * MiB);
set_range_uc(top_of_ram - 4 * MiB, 4 * MiB);
set_range_uc(top_of_ram - 8 * MiB, 4 * MiB);
}
static void recover_postcar_frame(struct postcar_frame *pcf)
{
msr_t base, mask;
int i;
int s3resume = romstage_handoff_is_resume();
/* Replicate non-UC MTRRs as left behind by AGESA.
*/
for (i = 0; i < pcf->mtrr->max_var_mtrrs; i++) {
mask = rdmsr(MTRR_PHYS_MASK(i));
base = rdmsr(MTRR_PHYS_BASE(i));
u32 size = ~(mask.lo & ~0xfff) + 1;
u8 type = base.lo & 0x7;
base.lo &= ~0xfff;
if (!(mask.lo & MTRR_PHYS_MASK_VALID) ||
(type == MTRR_TYPE_UNCACHEABLE))
continue;
postcar_frame_add_mtrr(pcf, base.lo, size, type);
}
/* For S3 resume path, INIT_RESUME does not return with
* memory covering CBMEM set as WB cacheable. For better
* speed make them WB after CAR teardown.
*/
if (s3resume) {
uintptr_t top_of_ram = (uintptr_t) cbmem_top();
top_of_ram = ALIGN_DOWN(top_of_ram, 4*MiB);
postcar_frame_add_mtrr(pcf, top_of_ram - 4*MiB, 4*MiB,
MTRR_TYPE_WRBACK);
postcar_frame_add_mtrr(pcf, top_of_ram - 8*MiB, 4*MiB,
MTRR_TYPE_WRBACK);
}
}
void fill_postcar_frame(struct postcar_frame *pcf)
{
pcf->skip_common_mtrr = 1;
recover_postcar_frame(pcf);
}