summaryrefslogtreecommitdiffstats
path: root/src/mainboard/google/poppy/romstage.c
blob: 0c1fc0213315e509059968d6e8e2ea6f8726b17b (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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/* SPDX-License-Identifier: GPL-2.0-only */

#include <assert.h>
#include <baseboard/variants.h>
#include <cbfs.h>
#include <console/console.h>
#include <soc/gpio.h>
#include <soc/romstage.h>
#include <string.h>
#include <variant/gpio.h>

#include <fsp/soc_binding.h>

/* Offset to identify DRAM type. */
#define SPD_DRAM_TYPE_OFF	2
#define SPD_DRAM_LPDDR3	0xf1
#define SPD_DRAM_DDR4		0x0c

/* Length of SPD data. */
#define SPD_LEN_LPDDR3		256
#define SPD_LEN_DDR4		512

/* Fields that are common across different memory types. */
#define SPD_DENSITY_BANKS_OFF	4
#define SPD_ADDRESSING_OFF	5
#define SPD_PART_LEN		18

/* Fields that are different depending upon memory type. */
#define SPD_ORG_OFF_LPDDR3	7
#define SPD_BUSW_OFF_LPDDR3	8
#define SPD_PART_OFF_LPDDR3	128

#define SPD_ORG_OFF_DDR4	12
#define SPD_BUSW_OFF_DDR4	13
#define SPD_PART_OFF_DDR4	329

#define SPD_INFO(_type)				\
	[MEMORY_##_type] = {				\
		.str = #_type,				\
		.type_code = SPD_DRAM_##_type,		\
		.len = SPD_LEN_##_type,		\
		.org_off = SPD_ORG_OFF_##_type,	\
		.busw_off = SPD_BUSW_OFF_##_type,	\
		.part_off = SPD_PART_OFF_##_type,	\
	}

static const struct dram_info {
	const char *str;
	uint16_t type_code;
	uint16_t len;
	uint16_t org_off;
	uint16_t busw_off;
	uint16_t part_off;
} spd_info[MEMORY_COUNT] = {
	SPD_INFO(LPDDR3),
	SPD_INFO(DDR4),
};

static void mainboard_print_spd_info(const uint8_t *spd, enum memory_type type)
{
	const int spd_banks[8] = {  8, 16, 32, 64, -1, -1, -1, -1 };
	const int spd_capmb[8] = {  1,  2,  4,  8, 16, 32, 64,  0 };
	const int spd_rows[8]  = { 12, 13, 14, 15, 16, -1, -1, -1 };
	const int spd_cols[8]  = {  9, 10, 11, 12, -1, -1, -1, -1 };
	const int spd_ranks[8] = {  1,  2,  3,  4, -1, -1, -1, -1 };
	const int spd_devw[8]  = {  4,  8, 16, 32, -1, -1, -1, -1 };
	const int spd_busw[8]  = {  8, 16, 32, 64, -1, -1, -1, -1 };
	char spd_name[SPD_PART_LEN+1] = { 0 };
	const struct dram_info *info = &spd_info[type];

	assert (info->type_code == spd[SPD_DRAM_TYPE_OFF]);

	/* Module type */
	printk(BIOS_INFO, "SPD: module type is %s\n", info->str);

	int banks = spd_banks[(spd[SPD_DENSITY_BANKS_OFF] >> 4) & 7];
	int capmb = spd_capmb[spd[SPD_DENSITY_BANKS_OFF] & 7] * 256;
	int rows  = spd_rows[(spd[SPD_ADDRESSING_OFF] >> 3) & 7];
	int cols  = spd_cols[spd[SPD_ADDRESSING_OFF] & 7];
	int ranks = spd_ranks[(spd[info->org_off] >> 3) & 7];
	int devw  = spd_devw[spd[info->org_off] & 7];
	int busw  = spd_busw[spd[info->busw_off] & 7];

	/* Module Part Number */
	memcpy(spd_name, &spd[info->part_off], SPD_PART_LEN);
	spd_name[SPD_PART_LEN] = 0;
	printk(BIOS_INFO, "SPD: module part is %s\n", spd_name);

	printk(BIOS_INFO,
		"SPD: banks %d, ranks %d, rows %d, columns %d, density %d Mb\n",
		banks, ranks, rows, cols, capmb);
	printk(BIOS_INFO, "SPD: device width %d bits, bus width %d bits\n",
		devw, busw);

	if (capmb > 0 && busw > 0 && devw > 0 && ranks > 0) {
		/* SIZE = DENSITY / 8 * BUS_WIDTH / SDRAM_WIDTH * RANKS */
		printk(BIOS_INFO, "SPD: module size is %u MB (per channel)\n",
			capmb / 8 * busw / devw * ranks);
	}
}

static uintptr_t mainboard_get_spd_data(enum memory_type type, bool use_sec_spd)
{
	char *spd_file;
	size_t spd_file_len;
	int spd_index;
	const size_t spd_len = spd_info[type].len;
	const char *spd_bin = use_sec_spd ? "sec-spd.bin" : "spd.bin";

	spd_index = variant_memory_sku();
	assert(spd_index >= 0);
	printk(BIOS_INFO, "SPD index %d\n", spd_index);

	/* Load SPD data from CBFS */
	spd_file = cbfs_boot_map_with_leak(spd_bin, CBFS_TYPE_SPD,
					   &spd_file_len);
	if (!spd_file)
		die("SPD data not found.");

	/* make sure we have at least one SPD in the file. */
	if (spd_file_len < spd_len)
		die("Missing SPD data.");

	/* Make sure we did not overrun the buffer */
	if (spd_file_len < ((spd_index + 1) * spd_len))
		die("Invalid SPD index.");

	spd_index *= spd_len;
	mainboard_print_spd_info((uint8_t *)(spd_file + spd_index), type);

	return (uintptr_t)(spd_file + spd_index);
}

void mainboard_memory_init_params(FSPM_UPD *mupd)
{
	FSP_M_CONFIG *mem_cfg = &mupd->FspmConfig;
	struct memory_params p;

	const struct pad_config *pads;
	size_t num;

	pads = variant_romstage_gpio_table(&num);
	gpio_configure_pads(pads, num);

	memset(&p, 0, sizeof(p));
	variant_memory_params(&p);

	assert(p.type < MEMORY_COUNT);

	if (p.dq_map && p.dq_map_size)
		memcpy(&mem_cfg->DqByteMapCh0, p.dq_map, p.dq_map_size);

	if (p.dqs_map && p.dqs_map_size)
		memcpy(&mem_cfg->DqsMapCpu2DramCh0, p.dqs_map, p.dqs_map_size);

	memcpy(&mem_cfg->RcompResistor, p.rcomp_resistor,
		p.rcomp_resistor_size);
	memcpy(&mem_cfg->RcompTarget, p.rcomp_target, p.rcomp_target_size);

	mem_cfg->MemorySpdPtr00 = mainboard_get_spd_data(p.type, p.use_sec_spd);
	if (p.single_channel)
		mem_cfg->MemorySpdPtr10 = 0;
	else
		mem_cfg->MemorySpdPtr10 = mem_cfg->MemorySpdPtr00;
	mem_cfg->MemorySpdDataLen = spd_info[p.type].len;

	mem_cfg->SaOcSupport = p.enable_sa_oc_support;
	mem_cfg->SaVoltageOffset = p.sa_voltage_offset_val;
}