1 /* SPDX-License-Identifier: GPL-2.0-only */
2
3 #include <arch/romstage.h>
4 #include <cbmem.h>
5 #include <console/console.h>
6 #include <commonlib/helpers.h>
7 #include <cpu/cpu.h>
8 #include <cpu/x86/msr.h>
9 #include <cpu/x86/mtrr.h>
10 #include <northbridge/amd/agesa/agesa_helper.h>
11 #include <romstage_handoff.h>
12
set_range_uc(u32 base,u32 size)13 static void set_range_uc(u32 base, u32 size)
14 {
15 int i, max_var_mtrrs;
16 msr_t msr;
17 max_var_mtrrs = get_var_mtrr_count();
18
19 for (i = 0; i < max_var_mtrrs; i++) {
20 msr = rdmsr(MTRR_PHYS_MASK(i));
21 if (!(msr.lo & MTRR_PHYS_MASK_VALID))
22 break;
23 }
24 if (i == max_var_mtrrs)
25 die("Run out of unused MTRRs\n");
26
27 msr.hi = 0;
28 msr.lo = base | MTRR_TYPE_UNCACHEABLE;
29 wrmsr(MTRR_PHYS_BASE(i), msr);
30
31 msr.hi = (1 << (cpu_phys_address_size() - 32)) - 1;
32 msr.lo = ~(size - 1) | MTRR_PHYS_MASK_VALID;
33 wrmsr(MTRR_PHYS_MASK(i), msr);
34 }
35
fixup_cbmem_to_UC(int s3resume)36 void fixup_cbmem_to_UC(int s3resume)
37 {
38 if (s3resume)
39 return;
40
41 /* For normal path, INIT_POST has returned with all
42 * memory set WB cacheable. But we need CBMEM as UC
43 * to make CAR teardown with invalidation without
44 * writeback possible.
45 */
46
47 const uintptr_t top_of_ram = ALIGN_UP(cbmem_top(), 4 * MiB);
48
49 set_range_uc(top_of_ram - 4 * MiB, 4 * MiB);
50 set_range_uc(top_of_ram - 8 * MiB, 4 * MiB);
51 }
52
recover_postcar_frame(struct postcar_frame * pcf)53 static void recover_postcar_frame(struct postcar_frame *pcf)
54 {
55 msr_t base, mask;
56 int i;
57 int s3resume = romstage_handoff_is_resume();
58
59 /* Replicate non-UC MTRRs as left behind by AGESA.
60 */
61 for (i = 0; i < pcf->mtrr->max_var_mtrrs; i++) {
62 mask = rdmsr(MTRR_PHYS_MASK(i));
63 base = rdmsr(MTRR_PHYS_BASE(i));
64 u32 size = ~(mask.lo & ~0xfff) + 1;
65 u8 type = base.lo & 0x7;
66 base.lo &= ~0xfff;
67
68 if (!(mask.lo & MTRR_PHYS_MASK_VALID) ||
69 (type == MTRR_TYPE_UNCACHEABLE))
70 continue;
71
72 postcar_frame_add_mtrr(pcf, base.lo, size, type);
73 }
74
75 /* For S3 resume path, INIT_RESUME does not return with
76 * memory covering CBMEM set as WB cacheable. For better
77 * speed make them WB after CAR teardown.
78 */
79 if (s3resume) {
80 uintptr_t top_of_ram = cbmem_top();
81 top_of_ram = ALIGN_DOWN(top_of_ram, 4 * MiB);
82
83 postcar_frame_add_mtrr(pcf, top_of_ram - 4 * MiB, 4 * MiB,
84 MTRR_TYPE_WRBACK);
85 postcar_frame_add_mtrr(pcf, top_of_ram - 8 * MiB, 4 * MiB,
86 MTRR_TYPE_WRBACK);
87 }
88 }
89
fill_postcar_frame(struct postcar_frame * pcf)90 void fill_postcar_frame(struct postcar_frame *pcf)
91 {
92 pcf->skip_common_mtrr = 1;
93 recover_postcar_frame(pcf);
94 }
95