summaryrefslogtreecommitdiff
path: root/src/soc/intel/common/basecode/ramtop/ramtop.c
blob: 83af44dbaa898642590a4dff24b1be44cc2c0010 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/* SPDX-License-Identifier: GPL-2.0-or-later */

#include <console/console.h>
#include <cpu/x86/mtrr.h>
#include <ip_checksum.h>
#include <intelbasecode/ramtop.h>
#include <pc80/mc146818rtc.h>
#include <stdint.h>

/* We need a region in CMOS to store the RAMTOP address */

#define RAMTOP_SIGNATURE   0x52544F50 /* 'RTOP' */

/*
 * Address of the ramtop byte in CMOS. Should be reserved
 * in mainboards' cmos.layout and not covered by checksum.
 */

#if CONFIG(USE_OPTION_TABLE)
#include "option_table.h"

#ifndef CMOS_VSTART_ramtop
#error "The `ramtop` CMOS entry is missing, please add it to your cmos.layout."
#endif

#if CMOS_VSTART_ramtop % 8 != 0
#error "The `ramtop` CMOS entry needs to be byte aligned, check your cmos.layout."
#endif	// CMOS_VSTART_ramtop % 8 != 0

#if CMOS_VLEN_ramtop != (10 * 8)
#error "The `ramtop` CMOS entry needs to be 10 bytes long, check your cmos.layout."
#endif	// CMOS_VLEN_ramtop != (10 * 8)

#else
#define CMOS_VSTART_ramtop 800
#endif	// CONFIG(USE_OPTION_TABLE)

struct ramtop_table {
	uint32_t signature;
	uint32_t addr;
	uint16_t checksum;
} __packed;

/* Read and validate ramtop_table structure from CMOS */
static int ramtop_cmos_read(struct ramtop_table *ramtop)
{
	u8 i, *p;
	u16 csum;

	for (p = (u8 *)ramtop, i = 0; i < sizeof(*ramtop); i++, p++)
		*p = cmos_read((CMOS_VSTART_ramtop / 8) + i);

	/* Verify signature */
	if (ramtop->signature != RAMTOP_SIGNATURE) {
		printk(BIOS_DEBUG, "ramtop_table invalid signature\n");
		return -1;
	}

	/* Verify checksum over signature and counter only */
	csum = compute_ip_checksum(ramtop, offsetof(struct ramtop_table, checksum));

	if (csum != ramtop->checksum) {
		printk(BIOS_DEBUG, "ramtop_table checksum mismatch\n");
		return -1;
	}

	return 0;
}

/* Write ramtop_table structure to CMOS */
static void ramtop_cmos_write(struct ramtop_table *ramtop)
{
	u8 i, *p;

	/* Checksum over signature and counter only */
	ramtop->checksum = compute_ip_checksum(
		ramtop, offsetof(struct ramtop_table, checksum));

	for (p = (u8 *)ramtop, i = 0; i < sizeof(*ramtop); i++, p++)
		cmos_write(*p, (CMOS_VSTART_ramtop / 8) + i);
}

/* Update the RAMTOP if required based on the input top_of_ram address */
void update_ramtop(uint32_t addr)
{
	struct ramtop_table ramtop;

	/* Read and update ramtop (if required) */
	if (ramtop_cmos_read(&ramtop) < 0) {
		/* Structure invalid, re-initialize */
		ramtop.signature = RAMTOP_SIGNATURE;
		ramtop.addr = 0;
	}

	/* Update ramtop if required */
	if (ramtop.addr == addr)
		return;

	ramtop.addr = addr;

	/* Write the new top_of_ram address to CMOS */
	ramtop_cmos_write(&ramtop);

	printk(BIOS_DEBUG, "Updated the RAMTOP address into CMOS 0x%x\n", ramtop.addr);
}

static uint32_t get_ramtop_addr(void)
{
	struct ramtop_table ramtop;

	if (ramtop_cmos_read(&ramtop) < 0)
		return 0;

	return ramtop.addr;
}

/* Early caching of top_of_ram region */
void early_ramtop_enable_cache_range(void)
{
	uint32_t ramtop = get_ramtop_addr();
	if (!ramtop)
		return;

	int mtrr = get_free_var_mtrr();
	if (mtrr == -1) {
		printk(BIOS_WARNING, "ramtop_table update failure due to no free MTRR available!\n");
		return;
	}
	/*
	 * We need to make sure late romstage (including FSP-M post mem) will be run
	 * cached. Caching 16MB below ramtop is a safe to cover late romstage.
	 */
	set_var_mtrr(mtrr, ramtop - 16 * MiB, 16 * MiB, MTRR_TYPE_WRBACK);
}